baritone/src/main/java/baritone/process/BuilderProcess.java

1039 lines
45 KiB
Java
Raw Normal View History

2018-12-26 05:07:17 +00:00
/*
* 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;
2018-12-26 05:07:17 +00:00
import baritone.api.process.PathingCommand;
import baritone.api.process.PathingCommandType;
2019-12-19 18:03:02 +00:00
import baritone.api.schematic.FillSchematic;
import baritone.api.schematic.SubstituteSchematic;
2019-10-11 23:15:14 +00:00
import baritone.api.schematic.ISchematic;
2019-12-24 23:20:00 +00:00
import baritone.api.schematic.IStaticSchematic;
import baritone.api.schematic.format.ISchematicFormat;
2019-11-24 19:11:21 +00:00
import baritone.api.utils.BetterBlockPos;
import baritone.api.utils.RayTraceUtils;
import baritone.api.utils.Rotation;
import baritone.api.utils.RotationUtils;
2019-01-09 04:45:02 +00:00
import baritone.api.utils.input.Input;
2018-12-26 05:07:17 +00:00
import baritone.pathing.movement.CalculationContext;
2019-02-07 00:22:40 +00:00
import baritone.pathing.movement.Movement;
2019-01-09 04:45:02 +00:00
import baritone.pathing.movement.MovementHelper;
2018-12-26 05:07:17 +00:00
import baritone.utils.BaritoneProcessHelper;
2019-02-07 00:22:40 +00:00
import baritone.utils.BlockStateInterface;
2018-12-26 05:07:17 +00:00
import baritone.utils.PathingCommandContext;
2019-08-20 18:23:23 +00:00
import baritone.utils.schematic.MapArtSchematic;
import baritone.utils.schematic.SelectionSchematic;
2019-12-24 23:20:00 +00:00
import baritone.utils.schematic.SchematicSystem;
2022-10-04 00:09:07 +00:00
import baritone.utils.schematic.format.defaults.LitematicaSchematic;
import baritone.utils.schematic.litematica.LitematicaHelper;
import baritone.utils.schematic.schematica.SchematicaHelper;
2021-12-21 19:09:22 +00:00
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
2021-12-21 19:09:22 +00:00
import net.minecraft.block.*;
2019-06-11 01:25:20 +00:00
import net.minecraft.item.BlockItem;
2019-03-14 03:09:08 +00:00
import net.minecraft.item.BlockItemUseContext;
2018-12-26 05:07:17 +00:00
import net.minecraft.item.ItemStack;
2019-03-14 03:09:08 +00:00
import net.minecraft.item.ItemUseContext;
2022-10-04 00:09:07 +00:00
import net.minecraft.nbt.CompressedStreamTools;
2022-03-22 22:26:40 +00:00
import net.minecraft.state.Property;
2019-06-10 19:43:02 +00:00
import net.minecraft.util.Direction;
2019-06-11 01:25:20 +00:00
import net.minecraft.util.Hand;
2019-01-09 04:45:02 +00:00
import net.minecraft.util.Tuple;
2021-01-30 04:13:56 +00:00
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.RayTraceResult;
2019-03-14 03:09:08 +00:00
import net.minecraft.util.math.shapes.VoxelShape;
2020-07-19 20:50:56 +00:00
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.util.math.vector.Vector3i;
2018-12-26 05:07:17 +00:00
import java.io.File;
2018-12-27 18:06:10 +00:00
import java.io.FileInputStream;
2022-10-04 00:09:07 +00:00
import java.nio.file.Files;
2019-01-09 04:45:02 +00:00
import java.util.*;
2021-01-15 11:52:25 +00:00
import java.util.stream.Collectors;
2018-12-26 05:07:17 +00:00
import static baritone.api.pathing.movement.ActionCosts.COST_INF;
2019-05-20 05:53:09 +00:00
public final class BuilderProcess extends BaritoneProcessHelper implements IBuilderProcess {
2018-12-26 05:07:17 +00:00
private HashSet<BetterBlockPos> incorrectPositions;
private LongOpenHashSet observedCompleted; // positions that are completed even if they're out of render distance and we can't make sure right now
2018-12-26 05:07:17 +00:00
private String name;
2019-04-11 22:17:26 +00:00
private ISchematic realSchematic;
2018-12-26 05:07:17 +00:00
private ISchematic schematic;
2020-07-19 20:50:56 +00:00
private Vector3i origin;
2019-02-07 00:22:40 +00:00
private int ticks;
2019-03-28 00:32:02 +00:00
private boolean paused;
2019-04-11 22:17:26 +00:00
private int layer;
2019-11-24 19:11:21 +00:00
private int numRepeats;
2019-10-07 00:02:41 +00:00
private List<BlockState> approxPlaceable;
2018-12-26 05:07:17 +00:00
2019-04-03 05:40:33 +00:00
public BuilderProcess(Baritone baritone) {
super(baritone);
}
2018-12-26 05:07:17 +00:00
@Override
2020-07-19 20:50:56 +00:00
public void build(String name, ISchematic schematic, Vector3i origin) {
this.name = name;
this.schematic = schematic;
2019-04-11 22:17:26 +00:00
this.realSchematic = null;
if (!Baritone.settings().buildSubstitutes.value.isEmpty()) {
this.schematic = new SubstituteSchematic(this.schematic, Baritone.settings().buildSubstitutes.value);
}
int x = origin.getX();
int y = origin.getY();
int z = origin.getZ();
if (Baritone.settings().schematicOrientationX.value) {
x += schematic.widthX();
}
if (Baritone.settings().schematicOrientationY.value) {
y += schematic.heightY();
}
if (Baritone.settings().schematicOrientationZ.value) {
z += schematic.lengthZ();
}
2020-07-19 20:50:56 +00:00
this.origin = new Vector3i(x, y, z);
2019-03-28 00:32:02 +00:00
this.paused = false;
this.layer = Baritone.settings().startAtLayer.value;
2019-11-24 19:11:21 +00:00
this.numRepeats = 0;
this.observedCompleted = new LongOpenHashSet();
this.incorrectPositions = null;
2019-03-28 00:32:02 +00:00
}
public void resume() {
paused = false;
}
2018-12-27 18:06:10 +00:00
2019-04-13 15:36:14 +00:00
public void pause() {
paused = true;
}
2019-08-30 18:55:25 +00:00
@Override
public boolean isPaused() {
return paused;
}
@Override
2020-07-19 20:50:56 +00:00
public boolean build(String name, File schematic, Vector3i origin) {
2019-12-24 23:20:00 +00:00
Optional<ISchematicFormat> format = SchematicSystem.INSTANCE.getByFile(schematic);
2019-12-18 16:24:43 +00:00
if (!format.isPresent()) {
2018-12-26 05:07:17 +00:00
return false;
}
2019-12-18 16:24:43 +00:00
ISchematic parsed;
try {
2019-12-27 07:14:31 +00:00
parsed = format.get().parse(new FileInputStream(schematic));
2019-12-18 16:24:43 +00:00
} catch (Exception e) {
e.printStackTrace();
2018-12-26 05:07:17 +00:00
return false;
}
2019-12-18 16:24:43 +00:00
if (Baritone.settings().mapArtMode.value) {
2019-12-24 23:20:00 +00:00
parsed = new MapArtSchematic((IStaticSchematic) parsed);
2019-12-18 16:24:43 +00:00
}
if (Baritone.settings().buildOnlySelection.value) {
parsed = new SelectionSchematic(parsed, origin, baritone.getSelectionManager().getSelections());
}
2019-12-18 16:24:43 +00:00
build(name, parsed, origin);
2018-12-26 05:07:17 +00:00
return true;
}
@Override
public void buildOpenSchematic() {
if (SchematicaHelper.isSchematicaPresent()) {
Optional<Tuple<IStaticSchematic, BlockPos>> schematic = SchematicaHelper.getOpenSchematic();
if (schematic.isPresent()) {
2020-01-01 01:40:14 +00:00
IStaticSchematic s = schematic.get().getA();
2021-10-20 01:20:41 +00:00
BlockPos origin = schematic.get().getB();
ISchematic schem = Baritone.settings().mapArtMode.value ? new MapArtSchematic(s) : s;
if (Baritone.settings().buildOnlySelection.value) {
schem = new SelectionSchematic(schem, origin, baritone.getSelectionManager().getSelections());
}
this.build(
2020-01-01 01:40:14 +00:00
schematic.get().getA().toString(),
schem,
origin
);
} else {
logDirect("No schematic currently open");
}
} else {
logDirect("Schematica is not present");
}
}
2022-10-04 00:09:07 +00:00
@Override
public void buildOpenLitematic(int i) {
if (LitematicaHelper.isLitematicaPresent()) {
//if java.lang.NoSuchMethodError is thrown see comment in SchematicPlacementManager
if (LitematicaHelper.hasLoadedSchematic()) {
String name = LitematicaHelper.getName(i);
try {
LitematicaSchematic schematic1 = new LitematicaSchematic(CompressedStreamTools.readCompressed(Files.newInputStream(LitematicaHelper.getSchematicFile(i).toPath())), false);
Vector3i correctedOrigin = LitematicaHelper.getCorrectedOrigin(schematic1, i);
LitematicaSchematic schematic2 = LitematicaHelper.blackMagicFuckery(schematic1, i);
build(name, schematic2, correctedOrigin);
} catch (Exception e) {
logDirect("Schematic File could not be loaded.");
}
} else {
logDirect("No schematic currently loaded");
}
} else {
logDirect("Litematica is not present");
}
}
2019-02-28 23:26:09 +00:00
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;
2019-09-01 22:53:13 +00:00
build("clear area", new FillSchematic(widthX, heightY, lengthZ, Blocks.AIR.getDefaultState()), origin);
2019-02-28 23:26:09 +00:00
}
2019-09-06 10:59:10 +00:00
@Override
2019-10-07 00:02:41 +00:00
public List<BlockState> getApproxPlaceable() {
2019-09-06 10:59:10 +00:00
return new ArrayList<>(approxPlaceable);
2019-02-28 23:26:09 +00:00
}
2018-12-26 05:07:17 +00:00
@Override
public boolean isActive() {
return schematic != null;
}
2019-10-07 00:02:41 +00:00
public BlockState placeAt(int x, int y, int z, BlockState current) {
2019-01-13 03:51:21 +00:00
if (!isActive()) {
return null;
}
2019-09-02 10:00:21 +00:00
if (!schematic.inSchematic(x - origin.getX(), y - origin.getY(), z - origin.getZ(), current)) {
2019-01-13 03:51:21 +00:00
return null;
}
2019-10-07 00:02:41 +00:00
BlockState state = schematic.desiredState(x - origin.getX(), y - origin.getY(), z - origin.getZ(), current, this.approxPlaceable);
2019-06-11 01:25:20 +00:00
if (state.getBlock() instanceof AirBlock) {
2019-01-13 03:51:21 +00:00
return null;
}
2019-01-15 03:49:26 +00:00
return state;
2019-01-13 03:51:21 +00:00
}
2019-04-29 21:59:25 +00:00
private Optional<Tuple<BetterBlockPos, Rotation>> toBreakNearPlayer(BuilderCalculationContext bcc) {
2019-01-09 04:45:02 +00:00
BetterBlockPos center = ctx.playerFeet();
2019-04-29 23:02:44 +00:00
BetterBlockPos pathStart = baritone.getPathingBehavior().pathStart();
2019-01-09 04:45:02 +00:00
for (int dx = -5; dx <= 5; dx++) {
2019-04-29 23:02:44 +00:00
for (int dy = Baritone.settings().breakFromAbove.value ? -1 : 0; dy <= 5; dy++) {
2019-01-09 04:45:02 +00:00
for (int dz = -5; dz <= 5; dz++) {
int x = center.x + dx;
int y = center.y + dy;
int z = center.z + dz;
2019-04-29 23:02:44 +00:00
if (dy == -1 && x == pathStart.x && z == pathStart.z) {
continue; // dont mine what we're supported by, but not directly standing on
}
2019-10-07 00:02:41 +00:00
BlockState desired = bcc.getSchematic(x, y, z, bcc.bsi.get0(x, y, z));
2019-01-09 04:45:02 +00:00
if (desired == null) {
continue; // irrelevant
}
2019-06-10 19:43:02 +00:00
BlockState curr = bcc.bsi.get0(x, y, z);
2020-03-08 02:37:47 +00:00
if (!(curr.getBlock() instanceof AirBlock) && !(curr.getBlock() == Blocks.WATER || curr.getBlock() == Blocks.LAVA) && !valid(curr, desired, false)) {
2019-01-09 04:45:02 +00:00
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();
}
2019-09-02 10:00:21 +00:00
public static class Placement {
2019-09-19 20:40:46 +00:00
2019-04-05 04:51:02 +00:00
private final int hotbarSelection;
private final BlockPos placeAgainst;
2019-06-10 19:43:02 +00:00
private final Direction side;
2019-04-05 04:51:02 +00:00
private final Rotation rot;
2019-02-07 00:22:40 +00:00
2019-06-10 19:43:02 +00:00
public Placement(int hotbarSelection, BlockPos placeAgainst, Direction side, Rotation rot) {
2019-02-07 00:22:40 +00:00
this.hotbarSelection = hotbarSelection;
this.placeAgainst = placeAgainst;
this.side = side;
this.rot = rot;
}
}
2019-06-10 19:43:02 +00:00
private Optional<Placement> searchForPlacables(BuilderCalculationContext bcc, List<BlockState> desirableOnHotbar) {
2019-02-07 00:22:40 +00:00
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;
2019-10-07 00:02:41 +00:00
BlockState desired = bcc.getSchematic(x, y, z, bcc.bsi.get0(x, y, z));
2019-02-07 00:22:40 +00:00
if (desired == null) {
continue; // irrelevant
}
2019-06-10 19:43:02 +00:00
BlockState curr = bcc.bsi.get0(x, y, z);
2020-03-07 23:34:27 +00:00
if (MovementHelper.isReplaceable(x, y, z, curr, bcc.bsi) && !valid(curr, desired, false)) {
2019-06-11 01:25:20 +00:00
if (dy == 1 && bcc.bsi.get0(x, y + 1, z).getBlock() instanceof AirBlock) {
2019-02-07 00:22:40 +00:00
continue;
}
2019-02-07 21:59:37 +00:00
desirableOnHotbar.add(desired);
2019-02-07 00:22:40 +00:00
Optional<Placement> opt = possibleToPlace(desired, x, y, z, bcc.bsi);
if (opt.isPresent()) {
return opt;
}
}
}
}
}
return Optional.empty();
}
2019-06-10 19:43:02 +00:00
public boolean placementPlausible(BlockPos pos, BlockState state) {
2019-03-14 03:09:08 +00:00
VoxelShape voxelshape = state.getCollisionShape(ctx.world(), pos);
return voxelshape.isEmpty() || ctx.world().checkNoEntityCollision(null, voxelshape.withOffset(pos.getX(), pos.getY(), pos.getZ()));
}
2019-06-10 19:43:02 +00:00
private Optional<Placement> possibleToPlace(BlockState toPlace, int x, int y, int z, BlockStateInterface bsi) {
for (Direction against : Direction.values()) {
2019-02-07 00:22:40 +00:00
BetterBlockPos placeAgainstPos = new BetterBlockPos(x, y, z).offset(against);
2019-06-10 19:43:02 +00:00
BlockState placeAgainstState = bsi.get0(placeAgainstPos);
2019-09-06 10:59:10 +00:00
if (MovementHelper.isReplaceable(placeAgainstPos.x, placeAgainstPos.y, placeAgainstPos.z, placeAgainstState, bsi)) {
2019-02-07 00:22:40 +00:00
continue;
}
2019-03-14 03:09:08 +00:00
if (!toPlace.isValidPosition(ctx.world(), new BetterBlockPos(x, y, z))) {
continue;
}
if (!placementPlausible(new BetterBlockPos(x, y, z), toPlace)) {
2019-02-07 00:22:40 +00:00
continue;
}
2019-03-14 03:09:08 +00:00
AxisAlignedBB aabb = placeAgainstState.getShape(ctx.world(), placeAgainstPos).getBoundingBox();
2020-07-19 20:50:56 +00:00
for (Vector3d placementMultiplier : aabbSideMultipliers(against)) {
2019-02-07 00:22:40 +00:00
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);
2020-07-19 20:50:56 +00:00
Rotation rot = RotationUtils.calcRotationFromVec3d(RayTraceUtils.inferSneakingEyePosition(ctx.player()), new Vector3d(placeX, placeY, placeZ), ctx.playerRotations());
RayTraceResult result = RayTraceUtils.rayTraceTowards(ctx.player(), rot, ctx.playerController().getBlockReachDistance(), true);
2019-06-11 01:25:20 +00:00
if (result != null && result.getType() == RayTraceResult.Type.BLOCK && ((BlockRayTraceResult) result).getPos().equals(placeAgainstPos) && ((BlockRayTraceResult) result).getFace() == against.getOpposite()) {
2019-02-07 00:22:40 +00:00
OptionalInt hotbar = hasAnyItemThatWouldPlace(toPlace, result, rot);
if (hotbar.isPresent()) {
return Optional.of(new Placement(hotbar.getAsInt(), placeAgainstPos, against.getOpposite(), rot));
}
}
}
}
return Optional.empty();
}
2019-06-10 19:43:02 +00:00
private OptionalInt hasAnyItemThatWouldPlace(BlockState desired, RayTraceResult result, Rotation rot) {
2019-02-07 00:22:40 +00:00
for (int i = 0; i < 9; i++) {
ItemStack stack = ctx.player().inventory.mainInventory.get(i);
2019-06-11 01:25:20 +00:00
if (stack.isEmpty() || !(stack.getItem() instanceof BlockItem)) {
2019-02-07 00:22:40 +00:00
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();
2019-03-14 03:09:08 +00:00
BlockItemUseContext meme = new BlockItemUseContext(new ItemUseContext(
2019-06-11 01:25:20 +00:00
ctx.world(),
2019-03-14 03:09:08 +00:00
ctx.player(),
2019-06-11 01:25:20 +00:00
Hand.MAIN_HAND,
2019-03-14 03:09:08 +00:00
stack,
2019-06-11 01:25:20 +00:00
(BlockRayTraceResult) result
) {}); // that {} gives us access to a protected constructor lmfao
BlockState wouldBePlaced = ((BlockItem) stack.getItem()).getBlock().getStateForPlacement(meme);
2019-02-07 00:22:40 +00:00
ctx.player().rotationYaw = originalYaw;
ctx.player().rotationPitch = originalPitch;
2019-03-14 03:09:08 +00:00
if (wouldBePlaced == null) {
continue;
}
if (!meme.canPlace()) {
continue;
}
2020-03-07 23:34:27 +00:00
if (valid(wouldBePlaced, desired, true)) {
2019-02-07 00:22:40 +00:00
return OptionalInt.of(i);
}
}
return OptionalInt.empty();
}
2020-07-19 20:50:56 +00:00
private static Vector3d[] aabbSideMultipliers(Direction side) {
2019-02-07 00:22:40 +00:00
switch (side) {
case UP:
2020-07-19 20:50:56 +00:00
return new Vector3d[]{new Vector3d(0.5, 1, 0.5), new Vector3d(0.1, 1, 0.5), new Vector3d(0.9, 1, 0.5), new Vector3d(0.5, 1, 0.1), new Vector3d(0.5, 1, 0.9)};
2019-02-07 00:22:40 +00:00
case DOWN:
2020-07-19 20:50:56 +00:00
return new Vector3d[]{new Vector3d(0.5, 0, 0.5), new Vector3d(0.1, 0, 0.5), new Vector3d(0.9, 0, 0.5), new Vector3d(0.5, 0, 0.1), new Vector3d(0.5, 0, 0.9)};
2019-02-07 00:22:40 +00:00
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;
2020-07-19 20:50:56 +00:00
return new Vector3d[]{new Vector3d(x, 0.25, z), new Vector3d(x, 0.75, z)};
2019-02-07 00:22:40 +00:00
default: // null
2019-04-04 06:19:32 +00:00
throw new IllegalStateException();
2019-02-07 00:22:40 +00:00
}
}
2018-12-26 05:07:17 +00:00
@Override
public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) {
2021-02-17 00:19:16 +00:00
return onTick(calcFailed, isSafeToCancel, 0);
}
public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel, int recursions) {
if (recursions > 1000) { // onTick calls itself, don't crash
return new PathingCommand(null, PathingCommandType.SET_GOAL_AND_PATH);
}
2019-09-06 10:59:10 +00:00
approxPlaceable = approxPlaceable(36);
2019-04-11 23:36:20 +00:00
if (baritone.getInputOverrideHandler().isInputForcedDown(Input.CLICK_LEFT)) {
ticks = 5;
} else {
ticks--;
}
2019-02-28 23:26:09 +00:00
baritone.getInputOverrideHandler().clearAllKeys();
2019-03-28 00:32:02 +00:00
if (paused) {
2019-04-17 05:43:33 +00:00
return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL);
2019-03-28 00:32:02 +00:00
}
2019-04-11 22:17:26 +00:00
if (Baritone.settings().buildInLayers.value) {
if (realSchematic == null) {
realSchematic = schematic;
}
2019-05-06 21:07:46 +00:00
ISchematic realSchematic = this.realSchematic; // wrap this properly, dont just have the inner class refer to the builderprocess.this
2019-05-14 23:03:11 +00:00
int minYInclusive;
int maxYInclusive;
// layer = 0 should be nothing
// layer = realSchematic.heightY() should be everything
if (Baritone.settings().layerOrder.value) { // top to bottom
maxYInclusive = realSchematic.heightY() - 1;
2021-06-24 21:33:48 +00:00
minYInclusive = realSchematic.heightY() - layer * Baritone.settings().layerHeight.value;
2019-05-14 23:03:11 +00:00
} else {
2021-06-24 21:33:48 +00:00
maxYInclusive = layer * Baritone.settings().layerHeight.value - 1;
2019-05-14 23:03:11 +00:00
minYInclusive = 0;
}
2019-04-11 22:17:26 +00:00
schematic = new ISchematic() {
@Override
2019-10-07 00:02:41 +00:00
public BlockState desiredState(int x, int y, int z, BlockState current, List<BlockState> approxPlaceable) {
2019-09-06 10:59:10 +00:00
return realSchematic.desiredState(x, y, z, current, BuilderProcess.this.approxPlaceable);
2019-04-11 22:17:26 +00:00
}
2019-05-14 23:03:11 +00:00
@Override
2019-10-07 00:02:41 +00:00
public boolean inSchematic(int x, int y, int z, BlockState currentState) {
2019-10-01 21:29:19 +00:00
return ISchematic.super.inSchematic(x, y, z, currentState) && y >= minYInclusive && y <= maxYInclusive && realSchematic.inSchematic(x, y, z, currentState);
2019-05-14 23:03:11 +00:00
}
@Override
2021-02-19 22:52:18 +00:00
public void reset() {
realSchematic.reset();
}
2019-04-11 22:17:26 +00:00
@Override
public int widthX() {
return realSchematic.widthX();
}
@Override
public int heightY() {
2019-05-14 23:03:11 +00:00
return realSchematic.heightY();
2019-04-11 22:17:26 +00:00
}
@Override
public int lengthZ() {
return realSchematic.lengthZ();
}
};
}
2019-01-13 03:51:21 +00:00
BuilderCalculationContext bcc = new BuilderCalculationContext();
2019-01-09 04:45:02 +00:00
if (!recalc(bcc)) {
2021-06-24 21:33:48 +00:00
if (Baritone.settings().buildInLayers.value && layer * Baritone.settings().layerHeight.value < realSchematic.heightY()) {
2019-04-11 22:17:26 +00:00
logDirect("Starting layer " + layer);
layer++;
2021-02-17 00:19:16 +00:00
return onTick(calcFailed, isSafeToCancel, recursions + 1);
2019-04-11 22:17:26 +00:00
}
2020-07-19 20:50:56 +00:00
Vector3i repeat = Baritone.settings().buildRepeat.value;
2019-11-24 19:11:21 +00:00
int max = Baritone.settings().buildRepeatCount.value;
numRepeats++;
2020-07-19 20:50:56 +00:00
if (repeat.equals(new Vector3i(0, 0, 0)) || (max != -1 && numRepeats >= max)) {
2019-04-11 23:36:20 +00:00
logDirect("Done building");
if (Baritone.settings().notificationOnBuildFinished.value) {
logNotification("Done building", false);
2020-02-29 16:28:18 +00:00
}
2019-04-11 23:36:20 +00:00
onLostControl();
return null;
}
// build repeat time
layer = 0;
2019-05-06 21:01:01 +00:00
origin = new BlockPos(origin).add(repeat);
if (!Baritone.settings().buildRepeatSneaky.value) {
schematic.reset();
}
2019-05-06 21:01:01 +00:00
logDirect("Repeating build in vector " + repeat + ", new origin is " + origin);
2021-02-17 00:19:16 +00:00
return onTick(calcFailed, isSafeToCancel, recursions + 1);
2019-01-09 04:45:02 +00:00
}
2019-08-23 07:21:29 +00:00
if (Baritone.settings().distanceTrim.value) {
trim();
}
2019-04-11 23:36:20 +00:00
2019-01-09 04:45:02 +00:00
Optional<Tuple<BetterBlockPos, Rotation>> toBreak = toBreakNearPlayer(bcc);
2020-07-26 03:53:22 +00:00
if (toBreak.isPresent() && isSafeToCancel && ctx.player().isOnGround()) {
2019-01-09 04:45:02 +00:00
// 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
2019-03-14 03:09:08 +00:00
Rotation rot = toBreak.get().getB();
BetterBlockPos pos = toBreak.get().getA();
2019-01-09 04:45:02 +00:00
baritone.getLookBehavior().updateTarget(rot, true);
MovementHelper.switchToBestToolFor(ctx, bcc.get(pos));
2020-02-06 01:45:22 +00:00
if (ctx.player().isCrouching()) {
2019-02-21 22:24:23 +00:00
// 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);
}
2019-04-16 00:12:20 +00:00
if (ctx.isLookingAt(pos) || ctx.playerRotations().isReallyCloseTo(rot)) {
2019-01-09 04:45:02 +00:00
baritone.getInputOverrideHandler().setInputForceState(Input.CLICK_LEFT, true);
}
2019-04-17 06:19:55 +00:00
return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL);
2019-01-09 04:45:02 +00:00
}
2019-06-10 19:43:02 +00:00
List<BlockState> desirableOnHotbar = new ArrayList<>();
2019-02-07 21:59:37 +00:00
Optional<Placement> toPlace = searchForPlacables(bcc, desirableOnHotbar);
2020-07-26 03:53:22 +00:00
if (toPlace.isPresent() && isSafeToCancel && ctx.player().isOnGround() && ticks <= 0) {
2019-02-07 00:22:40 +00:00
Rotation rot = toPlace.get().rot;
baritone.getLookBehavior().updateTarget(rot, true);
ctx.player().inventory.currentItem = toPlace.get().hotbarSelection;
baritone.getInputOverrideHandler().setInputForceState(Input.SNEAK, true);
2019-06-11 01:25:20 +00:00
if ((ctx.isLookingAt(toPlace.get().placeAgainst) && ((BlockRayTraceResult) ctx.objectMouseOver()).getFace().equals(toPlace.get().side)) || ctx.playerRotations().isReallyCloseTo(rot)) {
2019-02-07 00:22:40 +00:00
baritone.getInputOverrideHandler().setInputForceState(Input.CLICK_RIGHT, true);
}
2019-04-17 06:19:55 +00:00
return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL);
2019-02-07 00:22:40 +00:00
}
2019-01-09 04:45:02 +00:00
2019-03-12 06:29:39 +00:00
if (Baritone.settings().allowInventory.value) {
2019-02-07 21:59:37 +00:00
ArrayList<Integer> usefulSlots = new ArrayList<>();
2019-06-10 19:43:02 +00:00
List<BlockState> noValidHotbarOption = new ArrayList<>();
2019-02-07 21:59:37 +00:00
outer:
2019-06-10 19:43:02 +00:00
for (BlockState desired : desirableOnHotbar) {
2019-02-07 21:59:37 +00:00
for (int i = 0; i < 9; i++) {
2020-03-07 23:34:27 +00:00
if (valid(approxPlaceable.get(i), desired, true)) {
2019-02-07 21:59:37 +00:00
usefulSlots.add(i);
continue outer;
}
}
noValidHotbarOption.add(desired);
}
outer:
for (int i = 9; i < 36; i++) {
2019-06-10 19:43:02 +00:00
for (BlockState desired : noValidHotbarOption) {
2020-03-07 23:34:27 +00:00
if (valid(approxPlaceable.get(i), desired, true)) {
2019-02-07 21:59:37 +00:00
baritone.getInventoryBehavior().attemptToPutOnHotbar(i, usefulSlots::contains);
break outer;
}
}
}
}
2019-09-06 10:59:10 +00:00
Goal goal = assemble(bcc, approxPlaceable.subList(0, 9));
2019-01-09 23:07:06 +00:00
if (goal == null) {
2021-01-15 11:52:25 +00:00
goal = assemble(bcc, approxPlaceable, true); // we're far away, so assume that we have our whole inventory to recalculate placeable properly
2019-02-07 21:59:37 +00:00
if (goal == null) {
2021-06-24 21:33:48 +00:00
if (Baritone.settings().skipFailedLayers.value && Baritone.settings().buildInLayers.value && layer * Baritone.settings().layerHeight.value < realSchematic.heightY()) {
logDirect("Skipping layer that I cannot construct! Layer #" + layer);
layer++;
2021-02-17 00:19:16 +00:00
return onTick(calcFailed, isSafeToCancel, recursions + 1);
}
2019-03-28 00:32:02 +00:00
logDirect("Unable to do it. Pausing. resume to resume, cancel to cancel");
paused = true;
return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE);
2019-02-07 21:59:37 +00:00
}
2019-01-09 04:45:02 +00:00
}
2019-01-09 23:07:06 +00:00
return new PathingCommandContext(goal, PathingCommandType.FORCE_REVALIDATE_GOAL_AND_PATH, bcc);
2019-01-09 04:45:02 +00:00
}
2019-04-29 21:59:25 +00:00
private boolean recalc(BuilderCalculationContext bcc) {
2019-01-09 04:45:02 +00:00
if (incorrectPositions == null) {
incorrectPositions = new HashSet<>();
fullRecalc(bcc);
if (incorrectPositions.isEmpty()) {
return false;
}
}
recalcNearby(bcc);
if (incorrectPositions.isEmpty()) {
fullRecalc(bcc);
}
return !incorrectPositions.isEmpty();
}
2019-05-26 19:14:08 +00:00
private void trim() {
2019-02-20 06:50:03 +00:00
HashSet<BetterBlockPos> copy = new HashSet<>(incorrectPositions);
2020-07-26 03:53:22 +00:00
copy.removeIf(pos -> pos.distanceSq(ctx.player().getPosition()) > 200);
2019-02-20 06:50:03 +00:00
if (!copy.isEmpty()) {
incorrectPositions = copy;
}
}
2019-04-29 21:59:25 +00:00
private void recalcNearby(BuilderCalculationContext bcc) {
2019-01-09 04:45:02 +00:00
BetterBlockPos center = ctx.playerFeet();
int radius = Baritone.settings().builderTickScanRadius.value;
for (int dx = -radius; dx <= radius; dx++) {
for (int dy = -radius; dy <= radius; dy++) {
for (int dz = -radius; dz <= radius; dz++) {
2019-01-09 04:45:02 +00:00
int x = center.x + dx;
int y = center.y + dy;
int z = center.z + dz;
2019-10-07 00:02:41 +00:00
BlockState desired = bcc.getSchematic(x, y, z, bcc.bsi.get0(x, y, z));
2019-01-09 04:45:02 +00:00
if (desired != null) {
// we care about this position
BetterBlockPos pos = new BetterBlockPos(x, y, z);
2020-03-07 23:34:27 +00:00
if (valid(bcc.bsi.get0(x, y, z), desired, false)) {
incorrectPositions.remove(pos);
observedCompleted.add(BetterBlockPos.longHash(pos));
2019-01-09 04:45:02 +00:00
} else {
incorrectPositions.add(pos);
2019-05-01 19:15:31 +00:00
observedCompleted.remove(BetterBlockPos.longHash(pos));
2019-01-09 04:45:02 +00:00
}
}
}
}
}
}
2019-04-29 21:59:25 +00:00
private void fullRecalc(BuilderCalculationContext bcc) {
2019-01-09 04:45:02 +00:00
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++) {
int blockX = x + origin.getX();
int blockY = y + origin.getY();
int blockZ = z + origin.getZ();
2019-10-07 00:02:41 +00:00
BlockState current = bcc.bsi.get0(blockX, blockY, blockZ);
2019-09-02 10:00:21 +00:00
if (!schematic.inSchematic(x, y, z, current)) {
continue;
}
if (bcc.bsi.worldContainsLoadedChunk(blockX, blockZ)) { // check if its in render distance, not if its in cache
// we can directly observe this block, it is in render distance
2020-03-07 23:34:27 +00:00
if (valid(bcc.bsi.get0(blockX, blockY, blockZ), schematic.desiredState(x, y, z, current, this.approxPlaceable), false)) {
observedCompleted.add(BetterBlockPos.longHash(blockX, blockY, blockZ));
} else {
incorrectPositions.add(new BetterBlockPos(blockX, blockY, blockZ));
2019-05-01 19:15:31 +00:00
observedCompleted.remove(BetterBlockPos.longHash(blockX, blockY, blockZ));
2019-08-20 18:23:23 +00:00
if (incorrectPositions.size() > Baritone.settings().incorrectSize.value) {
return;
}
}
continue;
}
// this is not in render distance
if (!observedCompleted.contains(BetterBlockPos.longHash(blockX, blockY, blockZ))
&& !Baritone.settings().buildSkipBlocks.value.contains(schematic.desiredState(x, y, z, current, this.approxPlaceable).getBlock())) {
// and we've never seen this position be correct
// therefore mark as incorrect
incorrectPositions.add(new BetterBlockPos(blockX, blockY, blockZ));
2019-08-20 18:23:23 +00:00
if (incorrectPositions.size() > Baritone.settings().incorrectSize.value) {
return;
}
2019-01-09 04:45:02 +00:00
}
}
}
}
2018-12-26 05:07:17 +00:00
}
2019-10-07 00:02:41 +00:00
private Goal assemble(BuilderCalculationContext bcc, List<BlockState> approxPlaceable) {
2021-01-15 11:52:25 +00:00
return assemble(bcc, approxPlaceable, false);
}
2021-01-30 03:49:11 +00:00
private Goal assemble(BuilderCalculationContext bcc, List<BlockState> approxPlaceable, boolean logMissing) {
2019-09-02 10:00:21 +00:00
List<BetterBlockPos> placeable = new ArrayList<>();
List<BetterBlockPos> breakable = new ArrayList<>();
List<BetterBlockPos> sourceLiquids = new ArrayList<>();
2021-01-15 11:52:25 +00:00
List<BetterBlockPos> flowingLiquids = new ArrayList<>();
2021-01-30 03:49:11 +00:00
Map<BlockState, Integer> missing = new HashMap<>();
incorrectPositions.forEach(pos -> {
2019-06-10 19:43:02 +00:00
BlockState state = bcc.bsi.get0(pos);
2019-06-11 01:25:20 +00:00
if (state.getBlock() instanceof AirBlock) {
2019-09-06 10:59:10 +00:00
if (approxPlaceable.contains(bcc.getSchematic(pos.x, pos.y, pos.z, state))) {
2019-09-02 10:00:21 +00:00
placeable.add(pos);
2021-01-15 11:52:25 +00:00
} else {
2021-01-30 03:49:11 +00:00
BlockState desired = bcc.getSchematic(pos.x, pos.y, pos.z, state);
2021-01-15 11:52:25 +00:00
missing.put(desired, 1 + missing.getOrDefault(desired, 0));
}
} else {
2019-06-11 01:25:20 +00:00
if (state.getBlock() instanceof FlowingFluidBlock) {
// if the block itself is JUST a liquid (i.e. not just a waterlogged block), we CANNOT break it
// TODO for 1.13 make sure that this only matches pure water, not waterlogged blocks
if (!MovementHelper.possiblyFlowing(state)) {
// if it's a source block then we want to replace it with a throwaway
sourceLiquids.add(pos);
2021-01-15 11:52:25 +00:00
} else {
flowingLiquids.add(pos);
}
} else {
breakable.add(pos);
}
}
});
List<Goal> toBreak = new ArrayList<>();
breakable.forEach(pos -> toBreak.add(breakGoal(pos, bcc)));
List<Goal> toPlace = new ArrayList<>();
2019-09-02 10:00:21 +00:00
placeable.forEach(pos -> {
if (!placeable.contains(pos.down()) && !placeable.contains(pos.down(2))) {
toPlace.add(placementGoal(pos, bcc));
}
});
sourceLiquids.forEach(pos -> toPlace.add(new GoalBlock(pos.up())));
2019-01-09 23:07:06 +00:00
if (!toPlace.isEmpty()) {
return new JankyGoalComposite(new GoalComposite(toPlace.toArray(new Goal[0])), new GoalComposite(toBreak.toArray(new Goal[0])));
2019-01-09 23:07:06 +00:00
}
if (toBreak.isEmpty()) {
2021-01-15 11:52:25 +00:00
if (logMissing && !missing.isEmpty()) {
logDirect("Missing materials for at least:");
logDirect(missing.entrySet().stream()
2021-01-30 03:49:11 +00:00
.map(e -> String.format("%sx %s", e.getValue(), e.getKey()))
.collect(Collectors.joining("\n")));
2021-01-15 11:52:25 +00:00
}
if (logMissing && !flowingLiquids.isEmpty()) {
logDirect("Unreplaceable liquids at at least:");
logDirect(flowingLiquids.stream()
2021-01-30 03:49:11 +00:00
.map(p -> String.format("%s %s %s", p.x, p.y, p.z))
.collect(Collectors.joining("\n")));
2021-01-15 11:52:25 +00:00
}
2019-01-09 23:07:06 +00:00
return null;
}
return new GoalComposite(toBreak.toArray(new Goal[0]));
2019-01-09 23:07:06 +00:00
}
public static class JankyGoalComposite implements Goal {
2019-09-19 20:40:46 +00:00
2019-01-09 23:07:06 +00:00
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);
2019-01-09 04:45:02 +00:00
}
2019-02-21 22:24:23 +00:00
@Override
public String toString() {
return "JankyComposite Primary: " + primary + " Fallback: " + fallback;
}
2019-01-09 04:45:02 +00:00
}
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)
2019-01-09 22:36:44 +00:00
if (y > this.y) {
2019-01-09 04:45:02 +00:00
return false;
}
// but any other adjacent works for breaking, including inside or below
return super.isInGoal(x, y, z);
}
2018-12-26 05:07:17 +00:00
}
2019-04-29 23:02:44 +00:00
private Goal placementGoal(BlockPos pos, BuilderCalculationContext bcc) {
2019-06-11 01:25:20 +00:00
if (!(ctx.world().getBlockState(pos).getBlock() instanceof AirBlock)) { // TODO can this even happen?
2019-02-20 16:08:52 +00:00
return new GoalPlace(pos);
}
2019-06-11 01:25:20 +00:00
boolean allowSameLevel = !(ctx.world().getBlockState(pos.up()).getBlock() instanceof AirBlock);
2019-10-07 00:02:41 +00:00
BlockState current = ctx.world().getBlockState(pos);
2019-06-10 19:43:02 +00:00
for (Direction facing : Movement.HORIZONTALS_BUT_ALSO_DOWN_____SO_EVERY_DIRECTION_EXCEPT_UP) {
2019-09-02 10:00:21 +00:00
//noinspection ConstantConditions
2019-10-01 00:52:47 +00:00
if (MovementHelper.canPlaceAgainst(ctx, pos.offset(facing)) && placementPlausible(pos, bcc.getSchematic(pos.getX(), pos.getY(), pos.getZ(), current))) {
2019-08-20 18:23:23 +00:00
return new GoalAdjacent(pos, pos.offset(facing), allowSameLevel);
2019-02-07 00:22:40 +00:00
}
}
return new GoalPlace(pos);
}
2019-04-29 23:02:44 +00:00
private Goal breakGoal(BlockPos pos, BuilderCalculationContext bcc) {
2019-06-11 01:25:20 +00:00
if (Baritone.settings().goalBreakFromAbove.value && bcc.bsi.get0(pos.up()).getBlock() instanceof AirBlock && bcc.bsi.get0(pos.up(2)).getBlock() instanceof AirBlock) { // TODO maybe possible without the up(2) check?
2019-04-29 23:02:44 +00:00
return new JankyGoalComposite(new GoalBreak(pos), new GoalGetToBlock(pos.up()) {
@Override
public boolean isInGoal(int x, int y, int z) {
if (y > this.y || (x == this.x && y == this.y && z == this.z)) {
return false;
}
return super.isInGoal(x, y, z);
}
});
}
return new GoalBreak(pos);
}
2019-02-07 00:22:40 +00:00
public static class GoalAdjacent extends GoalGetToBlock {
2019-09-19 20:40:46 +00:00
2019-04-08 00:44:23 +00:00
private boolean allowSameLevel;
2019-08-20 18:23:23 +00:00
private BlockPos no;
2019-02-07 00:22:40 +00:00
2019-08-20 18:23:23 +00:00
public GoalAdjacent(BlockPos pos, BlockPos no, boolean allowSameLevel) {
2019-02-07 00:22:40 +00:00
super(pos);
2019-08-20 18:23:23 +00:00
this.no = no;
2019-02-07 00:22:40 +00:00
this.allowSameLevel = allowSameLevel;
}
public boolean isInGoal(int x, int y, int z) {
if (x == this.x && y == this.y && z == this.z) {
return false;
}
2019-08-20 18:23:23 +00:00
if (x == no.getX() && y == no.getY() && z == no.getZ()) {
return false;
}
2019-02-07 00:22:40 +00:00
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);
}
}
2019-01-09 22:36:44 +00:00
public static class GoalPlace extends GoalBlock {
2019-09-19 20:40:46 +00:00
2019-01-09 22:36:44 +00:00
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);
}
}
2018-12-26 05:07:17 +00:00
@Override
public void onLostControl() {
incorrectPositions = null;
name = null;
schematic = null;
2019-04-11 22:17:26 +00:00
realSchematic = null;
layer = Baritone.settings().startAtLayer.value;
2019-11-24 19:11:21 +00:00
numRepeats = 0;
2019-03-28 00:32:02 +00:00
paused = false;
observedCompleted = null;
2018-12-26 05:07:17 +00:00
}
@Override
2019-03-13 16:17:25 +00:00
public String displayName0() {
2019-03-28 00:32:02 +00:00
return paused ? "Builder Paused" : "Building " + name;
2018-12-26 05:07:17 +00:00
}
2019-10-07 00:02:41 +00:00
private List<BlockState> approxPlaceable(int size) {
2019-06-10 19:43:02 +00:00
List<BlockState> result = new ArrayList<>();
2019-02-07 21:59:37 +00:00
for (int i = 0; i < size; i++) {
2018-12-26 05:07:17 +00:00
ItemStack stack = ctx.player().inventory.mainInventory.get(i);
2019-06-11 01:25:20 +00:00
if (stack.isEmpty() || !(stack.getItem() instanceof BlockItem)) {
2018-12-26 05:07:17 +00:00
result.add(Blocks.AIR.getDefaultState());
continue;
}
// <toxic cloud>
2022-04-23 02:00:43 +00:00
BlockState itemState = ((BlockItem) stack.getItem())
.getBlock()
.getStateForPlacement(
2022-04-23 02:23:39 +00:00
new BlockItemUseContext(
new ItemUseContext(ctx.world(), ctx.player(), Hand.MAIN_HAND, stack, new BlockRayTraceResult(new Vector3d(ctx.player().getPositionVec().x, ctx.player().getPositionVec().y, ctx.player().getPositionVec().z), Direction.UP, ctx.playerFeet(), false)) {}
2022-04-23 02:00:43 +00:00
)
);
if (itemState != null) {
result.add(itemState);
} else {
2022-04-23 02:23:39 +00:00
result.add(Blocks.AIR.getDefaultState());
2022-04-23 02:00:43 +00:00
}
2018-12-26 05:07:17 +00:00
// </toxic cloud>
}
return result;
}
2022-03-22 22:26:40 +00:00
public static final Set<Property<?>> orientationProps =
2022-03-21 22:15:22 +00:00
ImmutableSet.of(RotatedPillarBlock.AXIS, HorizontalBlock.HORIZONTAL_FACING,
StairsBlock.FACING, StairsBlock.HALF, StairsBlock.SHAPE,
PaneBlock.NORTH, PaneBlock.EAST, PaneBlock.SOUTH, PaneBlock.WEST, VineBlock.UP,
TrapDoorBlock.OPEN, TrapDoorBlock.HALF
2021-12-21 19:09:22 +00:00
);
2022-03-21 22:15:22 +00:00
private boolean sameWithoutOrientation(BlockState first, BlockState second) {
2021-12-21 23:20:21 +00:00
if (first.getBlock() != second.getBlock()) {
return false;
}
2022-03-22 22:26:40 +00:00
ImmutableMap<Property<?>, Comparable<?>> map1 = first.getValues();
ImmutableMap<Property<?>, Comparable<?>> map2 = second.getValues();
for (Property<?> prop : map1.keySet()) {
2021-12-21 23:20:21 +00:00
if (map1.get(prop) != map2.get(prop) && !orientationProps.contains(prop)) {
return false;
}
2021-12-21 19:09:22 +00:00
}
return true;
}
2020-03-08 02:37:47 +00:00
private boolean valid(BlockState current, BlockState desired, boolean itemVerify) {
2019-03-14 23:06:32 +00:00
if (desired == null) {
return true;
}
if (current.getBlock() instanceof FlowingFluidBlock && Baritone.settings().okIfWater.value) {
2019-03-14 23:06:32 +00:00
return true;
}
2021-01-30 04:13:56 +00:00
if (current.getBlock() instanceof AirBlock && desired.getBlock() instanceof AirBlock) {
2020-06-28 05:25:47 +00:00
return true;
}
2021-01-30 03:49:11 +00:00
if (current.getBlock() instanceof AirBlock && Baritone.settings().okIfAir.value.contains(desired.getBlock())) {
2019-08-20 21:28:59 +00:00
return true;
}
2020-01-01 03:57:55 +00:00
if (desired.getBlock() instanceof AirBlock && Baritone.settings().buildIgnoreBlocks.value.contains(current.getBlock())) {
2019-12-14 04:09:04 +00:00
return true;
}
2020-03-08 02:37:47 +00:00
if (!(current.getBlock() instanceof AirBlock) && Baritone.settings().buildIgnoreExisting.value && !itemVerify) {
2019-12-14 04:09:04 +00:00
return true;
}
if (Baritone.settings().buildSkipBlocks.value.contains(desired.getBlock()) && !itemVerify) {
2021-01-12 22:59:11 +00:00
return true;
}
2021-03-09 11:31:02 +00:00
if (Baritone.settings().buildValidSubstitutes.value.getOrDefault(desired.getBlock(), Collections.emptyList()).contains(current.getBlock()) && !itemVerify) {
return true;
}
if (current.equals(desired)) {
return true;
}
2021-12-21 19:09:22 +00:00
return Baritone.settings().buildIgnoreDirection.value && sameWithoutOrientation(current, desired);
2019-01-09 04:45:02 +00:00
}
2018-12-26 05:07:17 +00:00
public class BuilderCalculationContext extends CalculationContext {
2019-09-19 20:40:46 +00:00
2019-10-07 00:02:41 +00:00
private final List<BlockState> placeable;
2018-12-26 05:07:17 +00:00
private final ISchematic schematic;
private final int originX;
private final int originY;
private final int originZ;
2019-01-13 03:51:21 +00:00
public BuilderCalculationContext() {
2018-12-26 05:07:17 +00:00
super(BuilderProcess.this.baritone, true); // wew lad
2019-09-06 10:59:10 +00:00
this.placeable = approxPlaceable(9);
2019-01-13 03:51:21 +00:00
this.schematic = BuilderProcess.this.schematic;
this.originX = origin.getX();
this.originY = origin.getY();
this.originZ = origin.getZ();
2019-01-09 22:36:44 +00:00
this.jumpPenalty += 10;
this.backtrackCostFavoringCoefficient = 1;
2018-12-26 05:07:17 +00:00
}
2019-10-07 00:02:41 +00:00
private BlockState getSchematic(int x, int y, int z, BlockState current) {
2019-09-02 10:00:21 +00:00
if (schematic.inSchematic(x - originX, y - originY, z - originZ, current)) {
2019-09-06 10:59:10 +00:00
return schematic.desiredState(x - originX, y - originY, z - originZ, current, BuilderProcess.this.approxPlaceable);
2018-12-26 05:07:17 +00:00
} else {
return null;
}
}
@Override
2019-10-07 00:36:25 +00:00
public double costOfPlacingAt(int x, int y, int z, BlockState current) {
2018-12-26 05:07:17 +00:00
if (isPossiblyProtected(x, y, z) || !worldBorder.canPlaceAt(x, z)) { // make calculation fail properly if we can't build
return COST_INF;
}
2019-10-07 00:36:25 +00:00
BlockState sch = getSchematic(x, y, z, current);
if (sch != null && !Baritone.settings().buildSkipBlocks.value.contains(sch.getBlock())) {
2018-12-26 05:07:17 +00:00
// TODO this can return true even when allowPlace is off.... is that an issue?
2019-06-11 01:25:20 +00:00
if (sch.getBlock() instanceof AirBlock) {
2019-01-09 04:45:02 +00:00
// 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
}
2019-09-06 10:59:10 +00:00
if (placeable.contains(sch)) {
2018-12-26 05:07:17 +00:00
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;
}
2019-01-09 04:45:02 +00:00
// we want it to be something that we don't have
// even more of a pain to place something wrong
return placeBlockCost * 3;
2018-12-26 05:07:17 +00:00
} else {
if (hasThrowaway) {
return placeBlockCost;
} else {
return COST_INF;
}
}
}
@Override
2019-10-07 00:36:25 +00:00
public double breakCostMultiplierAt(int x, int y, int z, BlockState current) {
2022-03-25 01:16:19 +00:00
if ((!allowBreak && !allowBreakAnyway.contains(current.getBlock())) || isPossiblyProtected(x, y, z)) {
2019-01-09 04:45:02 +00:00
return COST_INF;
2018-12-26 05:07:17 +00:00
}
2019-10-07 00:36:25 +00:00
BlockState sch = getSchematic(x, y, z, current);
if (sch != null && !Baritone.settings().buildSkipBlocks.value.contains(sch.getBlock())) {
2019-06-11 01:25:20 +00:00
if (sch.getBlock() instanceof AirBlock) {
2018-12-26 05:07:17 +00:00
// it should be air
// regardless of current contents, we can break it
2019-01-09 04:45:02 +00:00
return 1;
2018-12-26 05:07:17 +00:00
}
// it should be a real block
// is it already that block?
2020-03-07 23:34:27 +00:00
if (valid(bsi.get0(x, y, z), sch, false)) {
2019-08-20 18:23:23 +00:00
return Baritone.settings().breakCorrectBlockPenaltyMultiplier.value;
2019-01-09 04:45:02 +00:00
} 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;
}
2018-12-26 05:07:17 +00:00
// TODO do blocks in render distace only?
// TODO allow breaking blocks that we have a tool to harvest and immediately place back?
} else {
2019-01-09 04:45:02 +00:00
return 1; // why not lol
2018-12-26 05:07:17 +00:00
}
}
}
}