farmMaxScanSize = new Setting<>(256);
+
/**
* When the cache scan gives less blocks than the maximum threshold (but still above zero), scan the main world too.
*
@@ -1048,6 +1082,11 @@ public final class Settings {
*/
public final Setting breakCorrectBlockPenaltyMultiplier = new Setting<>(10d);
+ /**
+ * Multiply the cost of placing a block that's incorrect in the builder's schematic by this coefficient
+ */
+ public final Setting placeIncorrectBlockPenaltyMultiplier = new Setting<>(2d);
+
/**
* When this setting is true, build a schematic with the highest X coordinate being the origin, instead of the lowest
*/
@@ -1063,6 +1102,28 @@ public final class Settings {
*/
public final Setting schematicOrientationZ = new Setting<>(false);
+ /**
+ * Rotates the schematic before building it.
+ * Possible values are
+ *
+ * - NONE - No rotation
+ * - CLOCKWISE_90 - Rotate 90° clockwise
+ * - CLOCKWISE_180 - Rotate 180° clockwise
+ * - COUNTERCLOCKWISE_90 - Rotate 270° clockwise
+ *
+ */
+ public final Setting buildSchematicRotation = new Setting<>(Rotation.NONE);
+
+ /**
+ * Mirrors the schematic before building it.
+ * Possible values are
+ *
+ * - FRONT_BACK - mirror the schematic along its local x axis
+ * - LEFT_RIGHT - mirror the schematic along its local z axis
+ *
+ */
+ public final Setting buildSchematicMirror = new Setting<>(Mirror.NONE);
+
/**
* The fallback used by the build command when no extension is specified. This may be useful if schematics of a
* particular format are used often, and the user does not wish to have to specify the extension with every usage.
@@ -1174,6 +1235,11 @@ public final class Settings {
*/
public final Setting followRadius = new Setting<>(3);
+ /**
+ * The maximum distance to the entity you're following
+ */
+ public final Setting followTargetMaxDistance = new Setting<>(0);
+
/**
* Turn this on if your exploration filter is enormous, you don't want it to check if it's done,
* and you are just fine with it just hanging on completion
@@ -1209,8 +1275,12 @@ public final class Settings {
*/
@JavaOnly
public final Setting> logger = new Setting<>((msg) -> {
- final GuiMessageTag tag = useMessageTag.value ? Helper.MESSAGE_TAG : null;
- Minecraft.getInstance().gui.getChat().addMessage(msg, null, tag);
+ try {
+ final GuiMessageTag tag = useMessageTag.value ? Helper.MESSAGE_TAG : null;
+ Minecraft.getInstance().gui.getChat().addMessage(msg, null, tag);
+ } catch (Throwable t) {
+ LOGGER.warn("Failed to log message to chat: " + msg.getString(), t);
+ }
});
/**
@@ -1468,6 +1538,11 @@ public final class Settings {
*/
public final Setting elytraTermsAccepted = new Setting<>(false);
+ /**
+ * Verbose chat logging in elytra mode
+ */
+ public final Setting elytraChatSpam = new Setting<>(false);
+
/**
* A map of lowercase setting field names to their respective setting
*/
diff --git a/src/api/java/baritone/api/command/datatypes/BlockById.java b/src/api/java/baritone/api/command/datatypes/BlockById.java
index f92c968a2..64cf0a760 100644
--- a/src/api/java/baritone/api/command/datatypes/BlockById.java
+++ b/src/api/java/baritone/api/command/datatypes/BlockById.java
@@ -23,17 +23,11 @@ import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.Block;
-import java.util.regex.Pattern;
import java.util.stream.Stream;
public enum BlockById implements IDatatypeFor {
INSTANCE;
- /**
- * Matches (domain:)?name? where domain and name are [a-z0-9_.-]+ and [a-z0-9/_.-]+ respectively.
- */
- private static Pattern PATTERN = Pattern.compile("(?:[a-z0-9_.-]+:)?[a-z0-9/_.-]*");
-
@Override
public Block get(IDatatypeContext ctx) throws CommandException {
ResourceLocation id = new ResourceLocation(ctx.getConsumer().getString());
@@ -48,10 +42,6 @@ public enum BlockById implements IDatatypeFor {
public Stream tabComplete(IDatatypeContext ctx) throws CommandException {
String arg = ctx.getConsumer().getString();
- if (!PATTERN.matcher(arg).matches()) {
- return Stream.empty();
- }
-
return new TabCompleteHelper()
.append(
BuiltInRegistries.BLOCK.keySet()
diff --git a/src/api/java/baritone/api/command/datatypes/ItemById.java b/src/api/java/baritone/api/command/datatypes/ItemById.java
new file mode 100644
index 000000000..eb4f230b4
--- /dev/null
+++ b/src/api/java/baritone/api/command/datatypes/ItemById.java
@@ -0,0 +1,53 @@
+/*
+ * 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.api.command.datatypes;
+
+import baritone.api.command.exception.CommandException;
+import baritone.api.command.helpers.TabCompleteHelper;
+import net.minecraft.core.registries.BuiltInRegistries;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.world.item.Item;
+
+import java.util.stream.Stream;
+
+public enum ItemById implements IDatatypeFor- {
+ INSTANCE;
+
+ @Override
+ public Item get(IDatatypeContext ctx) throws CommandException {
+ ResourceLocation id = new ResourceLocation(ctx.getConsumer().getString());
+ Item item;
+ if ((item = BuiltInRegistries.ITEM.getOptional(id).orElse(null)) == null) {
+ throw new IllegalArgumentException("No item found by that id");
+ }
+ return item;
+ }
+
+ @Override
+ public Stream tabComplete(IDatatypeContext ctx) throws CommandException {
+ return new TabCompleteHelper()
+ .append(
+ BuiltInRegistries.BLOCK.keySet()
+ .stream()
+ .map(ResourceLocation::toString)
+ )
+ .filterPrefixNamespaced(ctx.getConsumer().getString())
+ .sortAlphabetically()
+ .stream();
+ }
+}
diff --git a/src/api/java/baritone/api/command/helpers/TabCompleteHelper.java b/src/api/java/baritone/api/command/helpers/TabCompleteHelper.java
index 4f822352a..88f603205 100644
--- a/src/api/java/baritone/api/command/helpers/TabCompleteHelper.java
+++ b/src/api/java/baritone/api/command/helpers/TabCompleteHelper.java
@@ -212,7 +212,12 @@ public class TabCompleteHelper {
* @return This {@link TabCompleteHelper}
*/
public TabCompleteHelper filterPrefixNamespaced(String prefix) {
- return filterPrefix(new ResourceLocation(prefix).toString());
+ ResourceLocation loc = ResourceLocation.tryParse(prefix);
+ if (loc == null) {
+ stream = Stream.empty();
+ return this;
+ }
+ return filterPrefix(loc.toString());
}
/**
diff --git a/src/api/java/baritone/api/pathing/goals/GoalRunAway.java b/src/api/java/baritone/api/pathing/goals/GoalRunAway.java
index 49b6f708d..1a1b6e50c 100644
--- a/src/api/java/baritone/api/pathing/goals/GoalRunAway.java
+++ b/src/api/java/baritone/api/pathing/goals/GoalRunAway.java
@@ -44,7 +44,7 @@ public class GoalRunAway implements Goal {
public GoalRunAway(double distance, Integer maintainY, BlockPos... from) {
if (from.length == 0) {
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException("Positions to run away from must not be empty");
}
this.from = from;
this.distanceSq = (int) (distance * distance);
diff --git a/src/api/java/baritone/api/process/IBuilderProcess.java b/src/api/java/baritone/api/process/IBuilderProcess.java
index 77250ce73..67a3ed491 100644
--- a/src/api/java/baritone/api/process/IBuilderProcess.java
+++ b/src/api/java/baritone/api/process/IBuilderProcess.java
@@ -24,6 +24,7 @@ import net.minecraft.core.Vec3i;
import net.minecraft.world.level.block.state.BlockState;
import java.io.File;
import java.util.List;
+import java.util.Optional;
/**
* @author Brady
@@ -74,4 +75,17 @@ public interface IBuilderProcess extends IBaritoneProcess {
* cause it to give up. This is updated every tick, but only while the builder process is active.
*/
List getApproxPlaceable();
+ /**
+ * Returns the lower bound of the current mining layer if mineInLayers is true.
+ * If mineInLayers is false, this will return an empty optional.
+ * @return The lower bound of the current mining layer
+ */
+ Optional getMinLayer();
+
+ /**
+ * Returns the upper bound of the current mining layer if mineInLayers is true.
+ * If mineInLayers is false, this will return an empty optional.
+ * @return The upper bound of the current mining layer
+ */
+ Optional getMaxLayer();
}
diff --git a/src/api/java/baritone/api/process/IFollowProcess.java b/src/api/java/baritone/api/process/IFollowProcess.java
index 6f7f0a239..e3ed73006 100644
--- a/src/api/java/baritone/api/process/IFollowProcess.java
+++ b/src/api/java/baritone/api/process/IFollowProcess.java
@@ -17,9 +17,11 @@
package baritone.api.process;
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.item.ItemStack;
+
import java.util.List;
import java.util.function.Predicate;
-import net.minecraft.world.entity.Entity;
/**
* @author Brady
@@ -34,6 +36,13 @@ public interface IFollowProcess extends IBaritoneProcess {
*/
void follow(Predicate filter);
+ /**
+ * Try to pick up any items matching this predicate
+ *
+ * @param filter the predicate
+ */
+ void pickup(Predicate filter);
+
/**
* @return The entities that are currently being followed. null if not currently following, empty if nothing matches the predicate
*/
diff --git a/src/api/java/baritone/api/schematic/ISchematicSystem.java b/src/api/java/baritone/api/schematic/ISchematicSystem.java
index c8f039070..385cc0514 100644
--- a/src/api/java/baritone/api/schematic/ISchematicSystem.java
+++ b/src/api/java/baritone/api/schematic/ISchematicSystem.java
@@ -21,6 +21,7 @@ import baritone.api.command.registry.Registry;
import baritone.api.schematic.format.ISchematicFormat;
import java.io.File;
+import java.util.List;
import java.util.Optional;
/**
@@ -41,4 +42,9 @@ public interface ISchematicSystem {
* @return The corresponding format for the file, {@link Optional#empty()} if no candidates were found.
*/
Optional getByFile(File file);
+
+ /**
+ * @return A list of file extensions used by supported formats
+ */
+ List getFileExtensions();
}
diff --git a/src/api/java/baritone/api/schematic/MirroredSchematic.java b/src/api/java/baritone/api/schematic/MirroredSchematic.java
new file mode 100644
index 000000000..b9e10808c
--- /dev/null
+++ b/src/api/java/baritone/api/schematic/MirroredSchematic.java
@@ -0,0 +1,114 @@
+/*
+ * 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.api.schematic;
+
+import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.level.block.Mirror;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class MirroredSchematic implements ISchematic {
+
+ private final ISchematic schematic;
+ private final Mirror mirror;
+
+ public MirroredSchematic(ISchematic schematic, Mirror mirror) {
+ this.schematic = schematic;
+ this.mirror = mirror;
+ }
+
+ @Override
+ public boolean inSchematic(int x, int y, int z, BlockState currentState) {
+ return schematic.inSchematic(
+ mirrorX(x, widthX(), mirror),
+ y,
+ mirrorZ(z, lengthZ(), mirror),
+ mirror(currentState, mirror)
+ );
+ }
+
+ @Override
+ public BlockState desiredState(int x, int y, int z, BlockState current, List approxPlaceable) {
+ return mirror(schematic.desiredState(
+ mirrorX(x, widthX(), mirror),
+ y,
+ mirrorZ(z, lengthZ(), mirror),
+ mirror(current, mirror),
+ mirror(approxPlaceable, mirror)
+ ), mirror);
+ }
+
+ @Override
+ public void reset() {
+ schematic.reset();
+ }
+
+ @Override
+ public int widthX() {
+ return schematic.widthX();
+ }
+
+ @Override
+ public int heightY() {
+ return schematic.heightY();
+ }
+
+ @Override
+ public int lengthZ() {
+ return schematic.lengthZ();
+ }
+
+ private static int mirrorX(int x, int sizeX, Mirror mirror) {
+ switch (mirror) {
+ case NONE:
+ case LEFT_RIGHT:
+ return x;
+ case FRONT_BACK:
+ return sizeX - x - 1;
+ }
+ throw new IllegalArgumentException("Unknown mirror");
+ }
+
+ private static int mirrorZ(int z, int sizeZ, Mirror mirror) {
+ switch (mirror) {
+ case NONE:
+ case FRONT_BACK:
+ return z;
+ case LEFT_RIGHT:
+ return sizeZ - z - 1;
+ }
+ throw new IllegalArgumentException("Unknown mirror");
+ }
+
+ private static BlockState mirror(BlockState state, Mirror mirror) {
+ if (state == null) {
+ return null;
+ }
+ return state.mirror(mirror);
+ }
+
+ private static List mirror(List states, Mirror mirror) {
+ if (states == null) {
+ return null;
+ }
+ return states.stream()
+ .map(s -> mirror(s, mirror))
+ .collect(Collectors.toList());
+ }
+}
diff --git a/src/api/java/baritone/api/schematic/RotatedSchematic.java b/src/api/java/baritone/api/schematic/RotatedSchematic.java
new file mode 100644
index 000000000..e3c9ed7aa
--- /dev/null
+++ b/src/api/java/baritone/api/schematic/RotatedSchematic.java
@@ -0,0 +1,136 @@
+/*
+ * 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.api.schematic;
+
+import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.level.block.Rotation;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class RotatedSchematic implements ISchematic {
+
+ private final ISchematic schematic;
+ private final Rotation rotation;
+ private final Rotation inverseRotation;
+
+ public RotatedSchematic(ISchematic schematic, Rotation rotation) {
+ this.schematic = schematic;
+ this.rotation = rotation;
+ // I don't think a 14 line switch would improve readability
+ this.inverseRotation = rotation.getRotated(rotation).getRotated(rotation);
+ }
+
+ @Override
+ public boolean inSchematic(int x, int y, int z, BlockState currentState) {
+ return schematic.inSchematic(
+ rotateX(x, z, widthX(), lengthZ(), inverseRotation),
+ y,
+ rotateZ(x, z, widthX(), lengthZ(), inverseRotation),
+ rotate(currentState, inverseRotation)
+ );
+ }
+
+ @Override
+ public BlockState desiredState(int x, int y, int z, BlockState current, List approxPlaceable) {
+ return rotate(schematic.desiredState(
+ rotateX(x, z, widthX(), lengthZ(), inverseRotation),
+ y,
+ rotateZ(x, z, widthX(), lengthZ(), inverseRotation),
+ rotate(current, inverseRotation),
+ rotate(approxPlaceable, inverseRotation)
+ ), rotation);
+ }
+
+ @Override
+ public void reset() {
+ schematic.reset();
+ }
+
+ @Override
+ public int widthX() {
+ return flipsCoordinates(rotation) ? schematic.lengthZ() : schematic.widthX();
+ }
+
+ @Override
+ public int heightY() {
+ return schematic.heightY();
+ }
+
+ @Override
+ public int lengthZ() {
+ return flipsCoordinates(rotation) ? schematic.widthX() : schematic.lengthZ();
+ }
+
+ /**
+ * Wether {@code rotation} swaps the x and z components
+ */
+ private static boolean flipsCoordinates(Rotation rotation) {
+ return rotation == Rotation.CLOCKWISE_90 || rotation == Rotation.COUNTERCLOCKWISE_90;
+ }
+
+ /**
+ * The x component of x,y after applying the rotation
+ */
+ private static int rotateX(int x, int z, int sizeX, int sizeZ, Rotation rotation) {
+ switch (rotation) {
+ case NONE:
+ return x;
+ case CLOCKWISE_90:
+ return sizeZ - z - 1;
+ case CLOCKWISE_180:
+ return sizeX - x - 1;
+ case COUNTERCLOCKWISE_90:
+ return z;
+ }
+ throw new IllegalArgumentException("Unknown rotation");
+ }
+
+ /**
+ * The z component of x,y after applying the rotation
+ */
+ private static int rotateZ(int x, int z, int sizeX, int sizeZ, Rotation rotation) {
+ switch (rotation) {
+ case NONE:
+ return z;
+ case CLOCKWISE_90:
+ return x;
+ case CLOCKWISE_180:
+ return sizeZ - z - 1;
+ case COUNTERCLOCKWISE_90:
+ return sizeX - x - 1;
+ }
+ throw new IllegalArgumentException("Unknown rotation");
+ }
+
+ private static BlockState rotate(BlockState state, Rotation rotation) {
+ if (state == null) {
+ return null;
+ }
+ return state.rotate(rotation);
+ }
+
+ private static List rotate(List states, Rotation rotation) {
+ if (states == null) {
+ return null;
+ }
+ return states.stream()
+ .map(s -> rotate(s, rotation))
+ .collect(Collectors.toList());
+ }
+}
diff --git a/src/api/java/baritone/api/schematic/format/ISchematicFormat.java b/src/api/java/baritone/api/schematic/format/ISchematicFormat.java
index 3fe045bcf..0ccf059b0 100644
--- a/src/api/java/baritone/api/schematic/format/ISchematicFormat.java
+++ b/src/api/java/baritone/api/schematic/format/ISchematicFormat.java
@@ -23,6 +23,7 @@ import baritone.api.schematic.IStaticSchematic;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.util.List;
/**
* The base of a {@link ISchematic} file format
@@ -42,4 +43,9 @@ public interface ISchematicFormat {
* @return Whether or not the specified file matches this schematic format
*/
boolean isFileType(File file);
+
+ /**
+ * @return A list of file extensions used by this format
+ */
+ List getFileExtensions();
}
diff --git a/src/api/java/baritone/api/utils/IPlayerContext.java b/src/api/java/baritone/api/utils/IPlayerContext.java
index a97475a5b..de6d7cd58 100644
--- a/src/api/java/baritone/api/utils/IPlayerContext.java
+++ b/src/api/java/baritone/api/utils/IPlayerContext.java
@@ -99,6 +99,14 @@ public interface IPlayerContext {
return new Rotation(player().getYRot(), player().getXRot());
}
+ /**
+ * Returns the player's eye height, taking into account whether or not the player is sneaking.
+ *
+ * @param ifSneaking Whether or not the player is sneaking
+ * @return The player's eye height
+ * @deprecated Use entity.getEyeHeight(Pose.CROUCHING) instead
+ */
+ @Deprecated
static double eyeHeight(boolean ifSneaking) {
return ifSneaking ? 1.27 : 1.62;
}
diff --git a/src/api/java/baritone/api/utils/RayTraceUtils.java b/src/api/java/baritone/api/utils/RayTraceUtils.java
index 5541f562b..354f9c87d 100644
--- a/src/api/java/baritone/api/utils/RayTraceUtils.java
+++ b/src/api/java/baritone/api/utils/RayTraceUtils.java
@@ -18,6 +18,7 @@
package baritone.api.utils;
import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.Pose;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;
@@ -62,6 +63,6 @@ public final class RayTraceUtils {
}
public static Vec3 inferSneakingEyePosition(Entity entity) {
- return new Vec3(entity.getX(), entity.getY() + IPlayerContext.eyeHeight(true), entity.getZ());
+ return new Vec3(entity.getX(), entity.getY() + entity.getEyeHeight(Pose.CROUCHING), entity.getZ());
}
}
diff --git a/src/api/java/baritone/api/utils/SettingsUtil.java b/src/api/java/baritone/api/utils/SettingsUtil.java
index 53283cd33..7a18b61c3 100644
--- a/src/api/java/baritone/api/utils/SettingsUtil.java
+++ b/src/api/java/baritone/api/utils/SettingsUtil.java
@@ -27,6 +27,9 @@ import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
+import net.minecraft.world.level.block.Mirror;
+import net.minecraft.world.level.block.Rotation;
+
import java.awt.*;
import java.io.BufferedReader;
import java.io.BufferedWriter;
@@ -149,7 +152,7 @@ public class SettingsUtil {
throw new IllegalStateException("Missing " + setting.getValueClass() + " " + setting.getName());
}
- return io.toString(new ParserContext(setting), value);
+ return io.toString(setting.getType(), value);
}
public static String settingValueToString(Settings.Setting setting) throws IllegalArgumentException {
@@ -196,7 +199,7 @@ public class SettingsUtil {
}
Class intendedType = setting.getValueClass();
ISettingParser ioMethod = Parser.getParser(setting.getType());
- Object parsed = ioMethod.parse(new ParserContext(setting), settingValue);
+ Object parsed = ioMethod.parse(setting.getType(), settingValue);
if (!intendedType.isInstance(parsed)) {
throw new IllegalStateException(ioMethod + " parser returned incorrect type, expected " + intendedType + " got " + parsed + " which is " + parsed.getClass());
}
@@ -205,26 +208,13 @@ public class SettingsUtil {
private interface ISettingParser {
- T parse(ParserContext context, String raw);
+ T parse(Type type, String raw);
- String toString(ParserContext context, T value);
+ String toString(Type type, T value);
boolean accepts(Type type);
}
- private static class ParserContext {
-
- private final Settings.Setting> setting;
-
- private ParserContext(Settings.Setting> setting) {
- this.setting = setting;
- }
-
- private Settings.Setting> getSetting() {
- return this.setting;
- }
- }
-
private enum Parser implements ISettingParser {
DOUBLE(Double.class, Double::parseDouble),
@@ -233,7 +223,8 @@ public class SettingsUtil {
FLOAT(Float.class, Float::parseFloat),
LONG(Long.class, Long::parseLong),
STRING(String.class, String::new),
- DIRECTION(Direction.class, Direction::byName),
+ MIRROR(Mirror.class, Mirror::valueOf, Mirror::name),
+ ROTATION(Rotation.class, Rotation::valueOf, Rotation::name),
COLOR(
Color.class,
str -> new Color(Integer.parseInt(str.split(",")[0]), Integer.parseInt(str.split(",")[1]), Integer.parseInt(str.split(",")[2])),
@@ -256,21 +247,21 @@ public class SettingsUtil {
),
LIST() {
@Override
- public Object parse(ParserContext context, String raw) {
- Type type = ((ParameterizedType) context.getSetting().getType()).getActualTypeArguments()[0];
- Parser parser = Parser.getParser(type);
+ public Object parse(Type type, String raw) {
+ Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0];
+ Parser parser = Parser.getParser(elementType);
return Stream.of(raw.split(","))
- .map(s -> parser.parse(context, s))
+ .map(s -> parser.parse(elementType, s))
.collect(Collectors.toList());
}
@Override
- public String toString(ParserContext context, Object value) {
- Type type = ((ParameterizedType) context.getSetting().getType()).getActualTypeArguments()[0];
- Parser parser = Parser.getParser(type);
+ public String toString(Type type, Object value) {
+ Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0];
+ Parser parser = Parser.getParser(elementType);
return ((List>) value).stream()
- .map(o -> parser.toString(context, o))
+ .map(o -> parser.toString(elementType, o))
.collect(Collectors.joining(","));
}
@@ -281,26 +272,26 @@ public class SettingsUtil {
},
MAPPING() {
@Override
- public Object parse(ParserContext context, String raw) {
- Type keyType = ((ParameterizedType) context.getSetting().getType()).getActualTypeArguments()[0];
- Type valueType = ((ParameterizedType) context.getSetting().getType()).getActualTypeArguments()[1];
+ public Object parse(Type type, String raw) {
+ Type keyType = ((ParameterizedType) type).getActualTypeArguments()[0];
+ Type valueType = ((ParameterizedType) type).getActualTypeArguments()[1];
Parser keyParser = Parser.getParser(keyType);
Parser valueParser = Parser.getParser(valueType);
return Stream.of(raw.split(",(?=[^,]*->)"))
.map(s -> s.split("->"))
- .collect(Collectors.toMap(s -> keyParser.parse(context, s[0]), s -> valueParser.parse(context, s[1])));
+ .collect(Collectors.toMap(s -> keyParser.parse(keyType, s[0]), s -> valueParser.parse(valueType, s[1])));
}
@Override
- public String toString(ParserContext context, Object value) {
- Type keyType = ((ParameterizedType) context.getSetting().getType()).getActualTypeArguments()[0];
- Type valueType = ((ParameterizedType) context.getSetting().getType()).getActualTypeArguments()[1];
+ public String toString(Type type, Object value) {
+ Type keyType = ((ParameterizedType) type).getActualTypeArguments()[0];
+ Type valueType = ((ParameterizedType) type).getActualTypeArguments()[1];
Parser keyParser = Parser.getParser(keyType);
Parser valueParser = Parser.getParser(valueType);
return ((Map, ?>) value).entrySet().stream()
- .map(o -> keyParser.toString(context, o.getKey()) + "->" + valueParser.toString(context, o.getValue()))
+ .map(o -> keyParser.toString(keyType, o.getKey()) + "->" + valueParser.toString(valueType, o.getValue()))
.collect(Collectors.joining(","));
}
@@ -331,14 +322,14 @@ public class SettingsUtil {
}
@Override
- public Object parse(ParserContext context, String raw) {
+ public Object parse(Type type, String raw) {
Object parsed = this.parser.apply(raw);
Objects.requireNonNull(parsed);
return parsed;
}
@Override
- public String toString(ParserContext context, Object value) {
+ public String toString(Type type, Object value) {
return this.toString.apply(value);
}
diff --git a/src/launch/java/baritone/launch/mixins/MixinPlayerController.java b/src/launch/java/baritone/launch/mixins/MixinPlayerController.java
index 34f39aee9..7a77d4849 100644
--- a/src/launch/java/baritone/launch/mixins/MixinPlayerController.java
+++ b/src/launch/java/baritone/launch/mixins/MixinPlayerController.java
@@ -31,6 +31,10 @@ public abstract class MixinPlayerController implements IPlayerControllerMP {
@Override
public abstract void setIsHittingBlock(boolean isHittingBlock);
+ @Accessor("isDestroying")
+ @Override
+ public abstract boolean isHittingBlock();
+
@Accessor("destroyBlockPos")
@Override
public abstract BlockPos getCurrentBlock();
@@ -38,4 +42,8 @@ public abstract class MixinPlayerController implements IPlayerControllerMP {
@Invoker("ensureHasSentCarriedItem")
@Override
public abstract void callSyncCurrentPlayItem();
+
+ @Accessor("destroyDelay")
+ @Override
+ public abstract void setDestroyDelay(int destroyDelay);
}
diff --git a/src/launch/java/baritone/launch/mixins/MixinScreen.java b/src/launch/java/baritone/launch/mixins/MixinScreen.java
index c99c7776c..84e72c7e0 100644
--- a/src/launch/java/baritone/launch/mixins/MixinScreen.java
+++ b/src/launch/java/baritone/launch/mixins/MixinScreen.java
@@ -21,17 +21,19 @@ import baritone.api.BaritoneAPI;
import baritone.api.IBaritone;
import baritone.api.event.events.ChatEvent;
import baritone.utils.accessor.IGuiScreen;
+import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.ClickEvent;
import net.minecraft.network.chat.Style;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
-
-import java.net.URI;
-import net.minecraft.client.gui.screens.Screen;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+import java.net.URI;
+
+import static baritone.api.command.IBaritoneChatControl.FORCE_COMMAND_PREFIX;
+
@Mixin(Screen.class)
public abstract class MixinScreen implements IGuiScreen {
@@ -47,9 +49,13 @@ public abstract class MixinScreen implements IGuiScreen {
if (clickEvent == null) {
return;
}
+ String command = clickEvent.getValue();
+ if (command == null || !command.startsWith(FORCE_COMMAND_PREFIX)) {
+ return;
+ }
IBaritone baritone = BaritoneAPI.getProvider().getPrimaryBaritone();
if (baritone != null) {
- baritone.getGameEventHandler().onSendChatMessage(new ChatEvent(clickEvent.getValue()));
+ baritone.getGameEventHandler().onSendChatMessage(new ChatEvent(command));
}
cir.setReturnValue(true);
cir.cancel();
diff --git a/src/main/java/baritone/Baritone.java b/src/main/java/baritone/Baritone.java
index c1176a3d4..ad6871413 100755
--- a/src/main/java/baritone/Baritone.java
+++ b/src/main/java/baritone/Baritone.java
@@ -79,7 +79,7 @@ public class Baritone implements IBaritone {
private final ExploreProcess exploreProcess;
private final FarmProcess farmProcess;
private final InventoryPauserProcess inventoryPauserProcess;
- private final ElytraProcess elytraProcess;
+ private final IElytraProcess elytraProcess;
private final PathingControlManager pathingControlManager;
private final SelectionManager selectionManager;
diff --git a/src/main/java/baritone/behavior/PathingBehavior.java b/src/main/java/baritone/behavior/PathingBehavior.java
index b7c035598..9e62765a2 100644
--- a/src/main/java/baritone/behavior/PathingBehavior.java
+++ b/src/main/java/baritone/behavior/PathingBehavior.java
@@ -265,7 +265,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
if (goal == null) {
return false;
}
- if (goal.isInGoal(ctx.playerFeet()) || goal.isInGoal(expectedSegmentStart)) {
+ if (goal.isInGoal(ctx.playerFeet())) {
return false;
}
synchronized (pathPlanLock) {
@@ -553,7 +553,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
});
}
- private static AbstractNodeCostSearch createPathfinder(BlockPos start, Goal goal, IPath previous, CalculationContext context) {
+ private AbstractNodeCostSearch createPathfinder(BlockPos start, Goal goal, IPath previous, CalculationContext context) {
Goal transformed = goal;
if (Baritone.settings().simplifyUnloadedYCoord.value && goal instanceof IGoalRenderPos) {
BlockPos pos = ((IGoalRenderPos) goal).getGoalPos();
@@ -562,7 +562,14 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
}
}
Favoring favoring = new Favoring(context.getBaritone().getPlayerContext(), previous, context);
- return new AStarPathFinder(start.getX(), start.getY(), start.getZ(), transformed, favoring, context);
+ BetterBlockPos feet = ctx.playerFeet();
+ var realStart = new BetterBlockPos(start);
+ var sub = feet.subtract(realStart);
+ if (feet.getY() == realStart.getY() && Math.abs(sub.getX()) <= 1 && Math.abs(sub.getZ()) <= 1) {
+ realStart = feet;
+ }
+ return new AStarPathFinder(realStart, start.getX(), start.getY(), start.getZ(), transformed, favoring, context);
+
}
@Override
diff --git a/src/main/java/baritone/cache/CachedWorld.java b/src/main/java/baritone/cache/CachedWorld.java
index e456382e6..aed1faeb5 100644
--- a/src/main/java/baritone/cache/CachedWorld.java
+++ b/src/main/java/baritone/cache/CachedWorld.java
@@ -196,9 +196,7 @@ public final class CachedWorld implements ICachedWorld, Helper {
int distZ = ((region.getZ() << 9) + 256) - pruneCenter.getZ();
double dist = Math.sqrt(distX * distX + distZ * distZ);
if (dist > 1024) {
- if (!Baritone.settings().censorCoordinates.value) {
- logDebug("Deleting cached region " + region.getX() + "," + region.getZ() + " from ram");
- }
+ logDebug("Deleting cached region from ram");
cachedRegions.remove(getRegionID(region.getX(), region.getZ()));
}
}
diff --git a/src/main/java/baritone/cache/FasterWorldScanner.java b/src/main/java/baritone/cache/FasterWorldScanner.java
index 694b482ab..e364fd7b4 100644
--- a/src/main/java/baritone/cache/FasterWorldScanner.java
+++ b/src/main/java/baritone/cache/FasterWorldScanner.java
@@ -20,6 +20,7 @@ package baritone.cache;
import baritone.api.cache.ICachedWorld;
import baritone.api.cache.IWorldScanner;
import baritone.api.utils.BetterBlockPos;
+import baritone.api.utils.BlockOptionalMeta;
import baritone.api.utils.BlockOptionalMetaLookup;
import baritone.api.utils.IPlayerContext;
import baritone.utils.accessor.IPalettedContainer;
@@ -31,7 +32,13 @@ import net.minecraft.util.BitStorage;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
-import net.minecraft.world.level.chunk.*;
+import net.minecraft.world.level.chunk.GlobalPalette;
+import net.minecraft.world.level.chunk.ChunkSource;
+import net.minecraft.world.level.chunk.LevelChunk;
+import net.minecraft.world.level.chunk.LevelChunkSection;
+import net.minecraft.world.level.chunk.Palette;
+import net.minecraft.world.level.chunk.PalettedContainer;
+import net.minecraft.world.level.chunk.SingleValuePalette;
import java.util.ArrayList;
import java.util.List;
@@ -41,6 +48,8 @@ import java.util.stream.Stream;
public enum FasterWorldScanner implements IWorldScanner {
INSTANCE;
+ private static final BlockState[] PALETTE_REGISTRY_SENTINEL = new BlockState[0];
+
@Override
public List scanChunkRadius(IPlayerContext ctx, BlockOptionalMetaLookup filter, int max, int yLevelThreshold, int maxSearchRadius) {
assert ctx.world() != null;
@@ -147,7 +156,7 @@ public enum FasterWorldScanner implements IWorldScanner {
long chunkX = (long) pos.x << 4;
long chunkZ = (long) pos.z << 4;
- int playerSectionY = ctx.playerFeet().y >> 4;
+ int playerSectionY = (ctx.playerFeet().y - ctx.world().getMinBuildHeight()) >> 4;
return collectChunkSections(lookup, chunkProvider.getChunk(pos.x, pos.z, false), chunkX, chunkZ, playerSectionY).stream();
}
@@ -183,7 +192,28 @@ public enum FasterWorldScanner implements IWorldScanner {
return;
}
- boolean[] isInFilter = getIncludedFilterIndices(lookup, ((IPalettedContainer) sectionContainer).getPalette());
+ Palette palette = ((IPalettedContainer) sectionContainer).getPalette();
+
+ if (palette instanceof SingleValuePalette) {
+ // single value palette doesn't have any data
+ if (lookup.has(palette.valueFor(0))) {
+ // TODO this is 4k hits, maybe don't return all of them?
+ for (int x = 0; x < 16; ++x) {
+ for (int y = 0; y < 16; ++y) {
+ for (int z = 0; z < 16; ++z) {
+ blocks.add(new BlockPos(
+ (int) chunkX + x,
+ sectionY + y,
+ (int) chunkZ + z
+ ));
+ }
+ }
+ }
+ }
+ return;
+ }
+
+ boolean[] isInFilter = getIncludedFilterIndices(lookup, palette);
if (isInFilter.length == 0) {
return;
}
@@ -212,13 +242,18 @@ public enum FasterWorldScanner implements IWorldScanner {
private boolean[] getIncludedFilterIndices(BlockOptionalMetaLookup lookup, Palette palette) {
boolean commonBlockFound = false;
- IdMapper paletteMap = getPalette(palette);
- int size = paletteMap.size();
+ BlockState[] paletteMap = getPalette(palette);
+
+ if (paletteMap == PALETTE_REGISTRY_SENTINEL) {
+ return getIncludedFilterIndicesFromRegistry(lookup);
+ }
+
+ int size = paletteMap.length;
boolean[] isInFilter = new boolean[size];
for (int i = 0; i < size; i++) {
- BlockState state = paletteMap.byId(i);
+ BlockState state = paletteMap[i];
if (lookup.has(state)) {
isInFilter[i] = true;
commonBlockFound = true;
@@ -233,21 +268,34 @@ public enum FasterWorldScanner implements IWorldScanner {
return isInFilter;
}
+ private boolean[] getIncludedFilterIndicesFromRegistry(BlockOptionalMetaLookup lookup) {
+ boolean[] isInFilter = new boolean[Block.BLOCK_STATE_REGISTRY.size()];
+
+ for (BlockOptionalMeta bom : lookup.blocks()) {
+ for (BlockState state : bom.getAllBlockStates()) {
+ isInFilter[Block.BLOCK_STATE_REGISTRY.getId(state)] = true;
+ }
+ }
+
+ return isInFilter;
+ }
+
/**
* cheats to get the actual map of id -> blockstate from the various palette implementations
*/
- private static IdMapper getPalette(Palette palette) {
+ private static BlockState[] getPalette(Palette palette) {
if (palette instanceof GlobalPalette) {
- return Block.BLOCK_STATE_REGISTRY;
+ // copying the entire registry is not nice so we treat it as a special case
+ return PALETTE_REGISTRY_SENTINEL;
} else {
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer());
palette.write(buf);
int size = buf.readVarInt();
- IdMapper states = new IdMapper<>();
+ BlockState[] states = new BlockState[size];
for (int i = 0; i < size; i++) {
BlockState state = Block.BLOCK_STATE_REGISTRY.byId(buf.readVarInt());
assert state != null;
- states.addMapping(state, i);
+ states[i] = state;
}
return states;
}
diff --git a/src/main/java/baritone/command/defaults/BuildCommand.java b/src/main/java/baritone/command/defaults/BuildCommand.java
index bb34254ae..f9ddd33ef 100644
--- a/src/main/java/baritone/command/defaults/BuildCommand.java
+++ b/src/main/java/baritone/command/defaults/BuildCommand.java
@@ -26,11 +26,13 @@ import baritone.api.command.datatypes.RelativeFile;
import baritone.api.command.exception.CommandException;
import baritone.api.command.exception.CommandInvalidStateException;
import baritone.api.utils.BetterBlockPos;
+import baritone.utils.schematic.SchematicSystem;
import org.apache.commons.io.FilenameUtils;
import java.io.File;
import java.util.Arrays;
import java.util.List;
+import java.util.StringJoiner;
import java.util.stream.Stream;
public class BuildCommand extends Command {
@@ -44,10 +46,29 @@ public class BuildCommand extends Command {
@Override
public void execute(String label, IArgConsumer args) throws CommandException {
- File file = args.getDatatypePost(RelativeFile.INSTANCE, schematicsDir).getAbsoluteFile();
+ final File file0 = args.getDatatypePost(RelativeFile.INSTANCE, schematicsDir).getAbsoluteFile();
+ File file = file0;
if (FilenameUtils.getExtension(file.getAbsolutePath()).isEmpty()) {
file = new File(file.getAbsolutePath() + "." + Baritone.settings().schematicFallbackExtension.value);
}
+ if (!file.exists()) {
+ if (file0.exists()) {
+ throw new CommandInvalidStateException(String.format(
+ "Cannot load %s because I do not know which schematic format"
+ + " that is. Please rename the file to include the correct"
+ + " file extension.",
+ file));
+ }
+ throw new CommandInvalidStateException("Cannot find " + file);
+ }
+ if (!SchematicSystem.INSTANCE.getByFile(file).isPresent()) {
+ StringJoiner formats = new StringJoiner(", ");
+ SchematicSystem.INSTANCE.getFileExtensions().forEach(formats::add);
+ throw new CommandInvalidStateException(String.format(
+ "Unsupported schematic format. Reckognized file extensions are: %s",
+ formats
+ ));
+ }
BetterBlockPos origin = ctx.playerFeet();
BetterBlockPos buildOrigin;
if (args.hasAny()) {
@@ -59,7 +80,7 @@ public class BuildCommand extends Command {
}
boolean success = baritone.getBuilderProcess().build(file.getName(), file, buildOrigin);
if (!success) {
- throw new CommandInvalidStateException("Couldn't load the schematic. Make sure to use the FULL file name, including the extension (e.g. blah.schematic).");
+ throw new CommandInvalidStateException("Couldn't load the schematic. Either your schematic is corrupt or this is a bug.");
}
logDirect(String.format("Successfully loaded schematic for building\nOrigin: %s", buildOrigin));
}
diff --git a/src/main/java/baritone/command/defaults/DefaultCommands.java b/src/main/java/baritone/command/defaults/DefaultCommands.java
index c810d07c1..5228a7ae1 100644
--- a/src/main/java/baritone/command/defaults/DefaultCommands.java
+++ b/src/main/java/baritone/command/defaults/DefaultCommands.java
@@ -53,6 +53,7 @@ public final class DefaultCommands {
new RenderCommand(baritone),
new FarmCommand(baritone),
new FollowCommand(baritone),
+ new PickupCommand(baritone),
new ExploreFilterCommand(baritone),
new ReloadAllCommand(baritone),
new SaveAllCommand(baritone),
diff --git a/src/main/java/baritone/command/defaults/ElytraCommand.java b/src/main/java/baritone/command/defaults/ElytraCommand.java
index 3f7b6bfd6..2f5eff352 100644
--- a/src/main/java/baritone/command/defaults/ElytraCommand.java
+++ b/src/main/java/baritone/command/defaults/ElytraCommand.java
@@ -216,7 +216,7 @@ public class ElytraCommand extends Command {
final String osArch = System.getProperty("os.arch");
final String osName = System.getProperty("os.name");
return String.format(
- "Legacy architectures are not supported. Your CPU is %s and your operating system is %s. " +
+ "Failed loading native library. Your CPU is %s and your operating system is %s. " +
"Supported architectures are 64 bit x86, and 64 bit ARM. Supported operating systems are Windows, " +
"Linux, and Mac",
osArch, osName
diff --git a/src/main/java/baritone/command/defaults/LitematicaCommand.java b/src/main/java/baritone/command/defaults/LitematicaCommand.java
index bfe0079b3..2e251b224 100644
--- a/src/main/java/baritone/command/defaults/LitematicaCommand.java
+++ b/src/main/java/baritone/command/defaults/LitematicaCommand.java
@@ -34,18 +34,9 @@ public class LitematicaCommand extends Command {
@Override
public void execute(String label, IArgConsumer args) throws CommandException {
- int schematic = 0;
- if (args.hasAny()) {
- args.requireMax(1);
- if (args.is(Integer.class)) {
- schematic = args.getAs(Integer.class) - 1;
- }
- }
- try {
- baritone.getBuilderProcess().buildOpenLitematic(schematic);
- } catch (IndexOutOfBoundsException e) {
- logDirect("Pleas provide a valid index.");
- }
+ args.requireMax(1);
+ int schematic = args.hasAny() ? args.getAs(Integer.class) - 1 : 0;
+ baritone.getBuilderProcess().buildOpenLitematic(schematic);
}
@Override
diff --git a/src/main/java/baritone/command/defaults/PickupCommand.java b/src/main/java/baritone/command/defaults/PickupCommand.java
new file mode 100644
index 000000000..7967dd023
--- /dev/null
+++ b/src/main/java/baritone/command/defaults/PickupCommand.java
@@ -0,0 +1,82 @@
+/*
+ * 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.command.defaults;
+
+import baritone.api.IBaritone;
+import baritone.api.command.Command;
+import baritone.api.command.argument.IArgConsumer;
+import baritone.api.command.datatypes.ItemById;
+import baritone.api.command.exception.CommandException;
+import net.minecraft.core.registries.BuiltInRegistries;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.world.item.Item;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Stream;
+
+public class PickupCommand extends Command {
+
+ public PickupCommand(IBaritone baritone) {
+ super(baritone, "pickup");
+ }
+
+ @Override
+ public void execute(String label, IArgConsumer args) throws CommandException {
+ Set
- collecting = new HashSet<>();
+ while (args.hasAny()) {
+ Item item = args.getDatatypeFor(ItemById.INSTANCE);
+ collecting.add(item);
+ }
+ if (collecting.isEmpty()) {
+ baritone.getFollowProcess().pickup(stack -> true);
+ logDirect("Picking up all items");
+ } else {
+ baritone.getFollowProcess().pickup(stack -> collecting.contains(stack.getItem()));
+ logDirect("Picking up these items:");
+ collecting.stream().map(BuiltInRegistries.ITEM::getKey).map(ResourceLocation::toString).forEach(this::logDirect);
+ }
+ }
+
+ @Override
+ public Stream tabComplete(String label, IArgConsumer args) throws CommandException {
+ while (args.has(2)) {
+ if (args.peekDatatypeOrNull(ItemById.INSTANCE) == null) {
+ return Stream.empty();
+ }
+ args.get();
+ }
+ return args.tabCompleteDatatype(ItemById.INSTANCE);
+ }
+
+ @Override
+ public String getShortDesc() {
+ return "Pickup items";
+ }
+
+ @Override
+ public List getLongDesc() {
+ return Arrays.asList(
+ "Usage:",
+ "> pickup - Pickup anything",
+ "> pickup <...> - Pickup certain items"
+ );
+ }
+}
diff --git a/src/main/java/baritone/command/defaults/SelCommand.java b/src/main/java/baritone/command/defaults/SelCommand.java
index 14d22b0b4..e789dcd97 100644
--- a/src/main/java/baritone/command/defaults/SelCommand.java
+++ b/src/main/java/baritone/command/defaults/SelCommand.java
@@ -227,12 +227,7 @@ public class SelCommand extends Command {
}
}
}
- ISchematic schematic = new StaticSchematic() {{
- states = blockstates;
- x = size.getX();
- y = size.getY();
- z = size.getZ();
- }};
+ ISchematic schematic = new StaticSchematic(blockstates);
composite.put(schematic, min.x - origin.x, min.y - origin.y, min.z - origin.z);
}
clipboard = composite;
diff --git a/src/main/java/baritone/pathing/calc/AStarPathFinder.java b/src/main/java/baritone/pathing/calc/AStarPathFinder.java
index b37b598ff..1c58cbf20 100644
--- a/src/main/java/baritone/pathing/calc/AStarPathFinder.java
+++ b/src/main/java/baritone/pathing/calc/AStarPathFinder.java
@@ -22,6 +22,7 @@ import baritone.api.pathing.calc.IPath;
import baritone.api.pathing.goals.Goal;
import baritone.api.pathing.movement.ActionCosts;
import baritone.api.utils.BetterBlockPos;
+import baritone.api.utils.SettingsUtil;
import baritone.pathing.calc.openset.BinaryHeapOpenSet;
import baritone.pathing.movement.CalculationContext;
import baritone.pathing.movement.Moves;
@@ -41,8 +42,8 @@ public final class AStarPathFinder extends AbstractNodeCostSearch {
private final Favoring favoring;
private final CalculationContext calcContext;
- public AStarPathFinder(int startX, int startY, int startZ, Goal goal, Favoring favoring, CalculationContext context) {
- super(startX, startY, startZ, goal, context);
+ public AStarPathFinder(BetterBlockPos realStart, int startX, int startY, int startZ, Goal goal, Favoring favoring, CalculationContext context) {
+ super(realStart, startX, startY, startZ, goal, context);
this.favoring = favoring;
this.calcContext = context;
}
@@ -96,7 +97,7 @@ public final class AStarPathFinder extends AbstractNodeCostSearch {
numNodes++;
if (goal.isInGoal(currentNode.x, currentNode.y, currentNode.z)) {
logDebug("Took " + (System.currentTimeMillis() - startTime) + "ms, " + numMovementsConsidered + " movements considered");
- return Optional.of(new Path(startNode, currentNode, numNodes, goal, calcContext));
+ return Optional.of(new Path(realStart, startNode, currentNode, numNodes, goal, calcContext));
}
for (Moves moves : allMoves) {
int newX = currentNode.x + moves.xOffset;
@@ -122,17 +123,39 @@ public final class AStarPathFinder extends AbstractNodeCostSearch {
continue;
}
if (actionCost <= 0 || Double.isNaN(actionCost)) {
- throw new IllegalStateException(moves + " calculated implausible cost " + actionCost);
+ throw new IllegalStateException(String.format(
+ "%s from %s %s %s calculated implausible cost %s",
+ moves,
+ SettingsUtil.maybeCensor(currentNode.x),
+ SettingsUtil.maybeCensor(currentNode.y),
+ SettingsUtil.maybeCensor(currentNode.z),
+ actionCost));
}
- // check destination after verifying it's not COST_INF -- some movements return a static IMPOSSIBLE object with COST_INF and destination being 0,0,0 to avoid allocating a new result for every failed calculation
+ // check destination after verifying it's not COST_INF -- some movements return COST_INF without adjusting the destination
if (moves.dynamicXZ && !worldBorder.entirelyContains(res.x, res.z)) { // see issue #218
continue;
}
if (!moves.dynamicXZ && (res.x != newX || res.z != newZ)) {
- throw new IllegalStateException(moves + " " + res.x + " " + newX + " " + res.z + " " + newZ);
+ throw new IllegalStateException(String.format(
+ "%s from %s %s %s ended at x z %s %s instead of %s %s",
+ moves,
+ SettingsUtil.maybeCensor(currentNode.x),
+ SettingsUtil.maybeCensor(currentNode.y),
+ SettingsUtil.maybeCensor(currentNode.z),
+ SettingsUtil.maybeCensor(res.x),
+ SettingsUtil.maybeCensor(res.z),
+ SettingsUtil.maybeCensor(newX),
+ SettingsUtil.maybeCensor(newZ)));
}
if (!moves.dynamicY && res.y != currentNode.y + moves.yOffset) {
- throw new IllegalStateException(moves + " " + res.y + " " + (currentNode.y + moves.yOffset));
+ throw new IllegalStateException(String.format(
+ "%s from %s %s %s ended at y %s instead of %s",
+ moves,
+ SettingsUtil.maybeCensor(currentNode.x),
+ SettingsUtil.maybeCensor(currentNode.y),
+ SettingsUtil.maybeCensor(currentNode.z),
+ SettingsUtil.maybeCensor(res.y),
+ SettingsUtil.maybeCensor(currentNode.y + moves.yOffset)));
}
long hashCode = BetterBlockPos.longHash(res.x, res.y, res.z);
if (isFavoring) {
diff --git a/src/main/java/baritone/pathing/calc/AbstractNodeCostSearch.java b/src/main/java/baritone/pathing/calc/AbstractNodeCostSearch.java
index d20b519dc..0bfb6ac3f 100644
--- a/src/main/java/baritone/pathing/calc/AbstractNodeCostSearch.java
+++ b/src/main/java/baritone/pathing/calc/AbstractNodeCostSearch.java
@@ -36,6 +36,7 @@ import java.util.Optional;
*/
public abstract class AbstractNodeCostSearch implements IPathFinder, Helper {
+ protected final BetterBlockPos realStart;
protected final int startX;
protected final int startY;
protected final int startZ;
@@ -81,7 +82,8 @@ public abstract class AbstractNodeCostSearch implements IPathFinder, Helper {
*/
protected static final double MIN_IMPROVEMENT = 0.01;
- AbstractNodeCostSearch(int startX, int startY, int startZ, Goal goal, CalculationContext context) {
+ AbstractNodeCostSearch(BetterBlockPos realStart, int startX, int startY, int startZ, Goal goal, CalculationContext context) {
+ this.realStart = realStart;
this.startX = startX;
this.startY = startY;
this.startZ = startZ;
@@ -177,7 +179,7 @@ public abstract class AbstractNodeCostSearch implements IPathFinder, Helper {
@Override
public Optional pathToMostRecentNodeConsidered() {
- return Optional.ofNullable(mostRecentConsidered).map(node -> new Path(startNode, node, 0, goal, context));
+ return Optional.ofNullable(mostRecentConsidered).map(node -> new Path(realStart, startNode, node, 0, goal, context));
}
@Override
@@ -208,7 +210,7 @@ public abstract class AbstractNodeCostSearch implements IPathFinder, Helper {
System.out.println("Path goes for " + Math.sqrt(dist) + " blocks");
logDebug("A* cost coefficient " + COEFFICIENTS[i]);
}
- return Optional.of(new Path(startNode, bestSoFar[i], numNodes, goal, context));
+ return Optional.of(new Path(realStart, startNode, bestSoFar[i], numNodes, goal, context));
}
}
// instead of returning bestSoFar[0], be less misleading
diff --git a/src/main/java/baritone/pathing/calc/Path.java b/src/main/java/baritone/pathing/calc/Path.java
index f7bfbaa24..eba408058 100644
--- a/src/main/java/baritone/pathing/calc/Path.java
+++ b/src/main/java/baritone/pathing/calc/Path.java
@@ -27,6 +27,7 @@ import baritone.pathing.movement.Movement;
import baritone.pathing.movement.Moves;
import baritone.pathing.path.CutoffPath;
import baritone.utils.pathing.PathBase;
+import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.Collections;
@@ -68,28 +69,40 @@ class Path extends PathBase {
private volatile boolean verified;
- Path(PathNode start, PathNode end, int numNodes, Goal goal, CalculationContext context) {
- this.start = new BetterBlockPos(start.x, start.y, start.z);
+ Path(BetterBlockPos realStart, PathNode start, PathNode end, int numNodes, Goal goal, CalculationContext context) {
this.end = new BetterBlockPos(end.x, end.y, end.z);
this.numNodes = numNodes;
this.movements = new ArrayList<>();
this.goal = goal;
this.context = context;
+
PathNode current = end;
- LinkedList tempPath = new LinkedList<>();
- LinkedList tempNodes = new LinkedList<>();
- // Repeatedly inserting to the beginning of an arraylist is O(n^2)
- // Instead, do it into a linked list, then convert at the end
+ List tempPath = new ArrayList<>();
+ List tempNodes = new ArrayList<>();
while (current != null) {
- tempNodes.addFirst(current);
- tempPath.addFirst(new BetterBlockPos(current.x, current.y, current.z));
+ tempNodes.add(current);
+ tempPath.add(new BetterBlockPos(current.x, current.y, current.z));
current = current.previous;
}
- // Can't directly convert from the PathNode pseudo linked list to an array because we don't know how long it is
- // inserting into a LinkedList keeps track of length, then when we addall (which calls .toArray) it's able
- // to performantly do that conversion since it knows the length.
- this.path = new ArrayList<>(tempPath);
- this.nodes = new ArrayList<>(tempNodes);
+
+ // If the position the player is at is different from the position we told A* to start from,
+ // and A* gave us no movements, then add a fake node that will allow a movement to be created
+ // that gets us to the single position in the path.
+ // See PathingBehavior#createPathfinder and https://github.com/cabaletta/baritone/pull/4519
+ var startNodePos = new BetterBlockPos(start.x, start.y, start.z);
+ if (!realStart.equals(startNodePos) && start.equals(end)) {
+ this.start = realStart;
+ PathNode fakeNode = new PathNode(realStart.x, realStart.y, realStart.z, goal);
+ fakeNode.cost = 0;
+ tempNodes.add(fakeNode);
+ tempPath.add(realStart);
+ } else {
+ this.start = startNodePos;
+ }
+
+ // Nodes are traversed last to first so we need to reverse the list
+ this.path = Lists.reverse(tempPath);
+ this.nodes = Lists.reverse(tempNodes);
}
@Override
@@ -99,7 +112,7 @@ class Path extends PathBase {
private boolean assembleMovements() {
if (path.isEmpty() || !movements.isEmpty()) {
- throw new IllegalStateException();
+ throw new IllegalStateException("Path must not be empty");
}
for (int i = 0; i < path.size() - 1; i++) {
double cost = nodes.get(i + 1).cost - nodes.get(i).cost;
@@ -132,7 +145,7 @@ class Path extends PathBase {
@Override
public IPath postProcess() {
if (verified) {
- throw new IllegalStateException();
+ throw new IllegalStateException("Path must not be verified twice");
}
verified = true;
boolean failed = assembleMovements();
@@ -141,7 +154,7 @@ class Path extends PathBase {
if (failed) { // at least one movement became impossible during calculation
CutoffPath res = new CutoffPath(this, movements().size());
if (res.movements().size() != movements.size()) {
- throw new IllegalStateException();
+ throw new IllegalStateException("Path has wrong size after cutoff");
}
return res;
}
@@ -153,7 +166,8 @@ class Path extends PathBase {
@Override
public List movements() {
if (!verified) {
- throw new IllegalStateException();
+ // edge case note: this is called during verification
+ throw new IllegalStateException("Path not yet verified");
}
return Collections.unmodifiableList(movements);
}
diff --git a/src/main/java/baritone/pathing/calc/PathNode.java b/src/main/java/baritone/pathing/calc/PathNode.java
index 2b693338a..0911c6c04 100644
--- a/src/main/java/baritone/pathing/calc/PathNode.java
+++ b/src/main/java/baritone/pathing/calc/PathNode.java
@@ -20,6 +20,7 @@ package baritone.pathing.calc;
import baritone.api.pathing.goals.Goal;
import baritone.api.pathing.movement.ActionCosts;
import baritone.api.utils.BetterBlockPos;
+import baritone.api.utils.SettingsUtil;
/**
* A node in the path, containing the cost and steps to get to it.
@@ -68,7 +69,12 @@ public final class PathNode {
this.cost = ActionCosts.COST_INF;
this.estimatedCostToGoal = goal.heuristic(x, y, z);
if (Double.isNaN(estimatedCostToGoal)) {
- throw new IllegalStateException(goal + " calculated implausible heuristic");
+ throw new IllegalStateException(String.format(
+ "%s calculated implausible heuristic NaN at %s %s %s",
+ goal,
+ SettingsUtil.maybeCensor(x),
+ SettingsUtil.maybeCensor(y),
+ SettingsUtil.maybeCensor(z)));
}
this.heapPosition = -1;
this.x = x;
diff --git a/src/main/java/baritone/pathing/calc/openset/BinaryHeapOpenSet.java b/src/main/java/baritone/pathing/calc/openset/BinaryHeapOpenSet.java
index 33f077b9d..1da8ed7e5 100644
--- a/src/main/java/baritone/pathing/calc/openset/BinaryHeapOpenSet.java
+++ b/src/main/java/baritone/pathing/calc/openset/BinaryHeapOpenSet.java
@@ -92,7 +92,7 @@ public final class BinaryHeapOpenSet implements IOpenSet {
@Override
public final PathNode removeLowest() {
if (size == 0) {
- throw new IllegalStateException();
+ throw new IllegalStateException("Cannot remove from empty heap");
}
PathNode result = array[1];
PathNode val = array[size];
diff --git a/src/main/java/baritone/pathing/movement/CalculationContext.java b/src/main/java/baritone/pathing/movement/CalculationContext.java
index 64aca2ceb..e84188a7f 100644
--- a/src/main/java/baritone/pathing/movement/CalculationContext.java
+++ b/src/main/java/baritone/pathing/movement/CalculationContext.java
@@ -161,6 +161,12 @@ public class CalculationContext {
if (!worldBorder.canPlaceAt(x, z)) {
return COST_INF;
}
+ if (!Baritone.settings().allowPlaceInFluidsSource.value && current.getFluidState().isSource()) {
+ return COST_INF;
+ }
+ if (!Baritone.settings().allowPlaceInFluidsFlow.value && !current.getFluidState().isEmpty() && !current.getFluidState().isSource()) {
+ return COST_INF;
+ }
return placeBlockCost;
}
diff --git a/src/main/java/baritone/pathing/movement/MovementHelper.java b/src/main/java/baritone/pathing/movement/MovementHelper.java
index f5c928cd4..211180c83 100644
--- a/src/main/java/baritone/pathing/movement/MovementHelper.java
+++ b/src/main/java/baritone/pathing/movement/MovementHelper.java
@@ -428,7 +428,7 @@ public interface MovementHelper extends ActionCosts, Helper {
if (block == Blocks.LADDER || (block == Blocks.VINE && Baritone.settings().allowVines.value)) { // TODO reconsider this
return YES;
}
- if (block == Blocks.FARMLAND || block == Blocks.DIRT_PATH) {
+ if (block == Blocks.FARMLAND || block == Blocks.DIRT_PATH || block == Blocks.SOUL_SAND) {
return YES;
}
if (block == Blocks.ENDER_CHEST || block == Blocks.CHEST || block == Blocks.TRAPPED_CHEST) {
diff --git a/src/main/java/baritone/pathing/movement/Moves.java b/src/main/java/baritone/pathing/movement/Moves.java
index 87b5db6ac..312c8957c 100644
--- a/src/main/java/baritone/pathing/movement/Moves.java
+++ b/src/main/java/baritone/pathing/movement/Moves.java
@@ -347,7 +347,7 @@ public enum Moves {
public void apply(CalculationContext context, int x, int y, int z, MutableMoveResult result) {
if (dynamicXZ || dynamicY) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException("Movements with dynamic offset must override `apply`");
}
result.x = x + xOffset;
result.y = y + yOffset;
@@ -356,6 +356,6 @@ public enum Moves {
}
public double cost(CalculationContext context, int x, int y, int z) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException("Movements must override `cost` or `apply`");
}
}
diff --git a/src/main/java/baritone/pathing/path/PathExecutor.java b/src/main/java/baritone/pathing/path/PathExecutor.java
index d760f3a38..8a5359b5b 100644
--- a/src/main/java/baritone/pathing/path/PathExecutor.java
+++ b/src/main/java/baritone/pathing/path/PathExecutor.java
@@ -455,7 +455,9 @@ public class PathExecutor implements IPathExecutor, Helper {
if (data != null) {
BetterBlockPos fallDest = new BetterBlockPos(data.getB());
if (!path.positions().contains(fallDest)) {
- throw new IllegalStateException();
+ throw new IllegalStateException(String.format(
+ "Fall override at %s %s %s returned illegal destination %s %s %s",
+ current.getSrc(), fallDest));
}
if (ctx.playerFeet().equals(fallDest)) {
pathPosition = path.positions().indexOf(fallDest);
@@ -603,7 +605,9 @@ public class PathExecutor implements IPathExecutor, Helper {
}
return SplicedPath.trySplice(path, next.path, false).map(path -> {
if (!path.getDest().equals(next.getPath().getDest())) {
- throw new IllegalStateException();
+ throw new IllegalStateException(String.format(
+ "Path has end %s instead of %s after splicing",
+ path.getDest(), next.getPath().getDest()));
}
PathExecutor ret = new PathExecutor(behavior, path);
ret.pathPosition = pathPosition;
@@ -619,7 +623,9 @@ public class PathExecutor implements IPathExecutor, Helper {
int cutoffAmt = Baritone.settings().pathHistoryCutoffAmount.value;
CutoffPath newPath = new CutoffPath(path, cutoffAmt, path.length() - 1);
if (!newPath.getDest().equals(path.getDest())) {
- throw new IllegalStateException();
+ throw new IllegalStateException(String.format(
+ "Path has end %s instead of %s after trimming its start",
+ newPath.getDest(), path.getDest()));
}
logDebug("Discarding earliest segment movements, length cut from " + path.length() + " to " + newPath.length());
PathExecutor ret = new PathExecutor(behavior, newPath);
diff --git a/src/main/java/baritone/pathing/path/SplicedPath.java b/src/main/java/baritone/pathing/path/SplicedPath.java
index 1ba497d81..7f083a662 100644
--- a/src/main/java/baritone/pathing/path/SplicedPath.java
+++ b/src/main/java/baritone/pathing/path/SplicedPath.java
@@ -92,7 +92,7 @@ public class SplicedPath extends PathBase {
}
int positionInSecond = second.positions().indexOf(first.positions().get(firstPositionInSecond));
if (!allowOverlapCutoff && positionInSecond != 0) {
- throw new IllegalStateException();
+ throw new IllegalStateException("Paths to be spliced are overlapping incorrectly");
}
List positions = new ArrayList<>();
List movements = new ArrayList<>();
diff --git a/src/main/java/baritone/process/BuilderProcess.java b/src/main/java/baritone/process/BuilderProcess.java
index c484140fc..094d80f69 100644
--- a/src/main/java/baritone/process/BuilderProcess.java
+++ b/src/main/java/baritone/process/BuilderProcess.java
@@ -28,7 +28,10 @@ import baritone.api.process.PathingCommandType;
import baritone.api.schematic.FillSchematic;
import baritone.api.schematic.ISchematic;
import baritone.api.schematic.IStaticSchematic;
+import baritone.api.schematic.MaskSchematic;
import baritone.api.schematic.SubstituteSchematic;
+import baritone.api.schematic.RotatedSchematic;
+import baritone.api.schematic.MirroredSchematic;
import baritone.api.schematic.format.ISchematicFormat;
import baritone.api.utils.*;
import baritone.api.utils.input.Input;
@@ -41,7 +44,6 @@ import baritone.utils.PathingCommandContext;
import baritone.utils.schematic.MapArtSchematic;
import baritone.utils.schematic.SelectionSchematic;
import baritone.utils.schematic.SchematicSystem;
-import baritone.utils.schematic.format.defaults.LitematicaSchematic;
import baritone.utils.schematic.litematica.LitematicaHelper;
import baritone.utils.schematic.schematica.SchematicaHelper;
import com.google.common.collect.ImmutableMap;
@@ -50,7 +52,6 @@ import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Vec3i;
-import net.minecraft.nbt.NbtIo;
import net.minecraft.util.Tuple;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.item.BlockItem;
@@ -75,7 +76,6 @@ import net.minecraft.world.phys.shapes.VoxelShape;
import java.io.File;
import java.io.FileInputStream;
-import java.nio.file.Files;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -84,6 +84,14 @@ import static baritone.api.pathing.movement.ActionCosts.COST_INF;
public final class BuilderProcess extends BaritoneProcessHelper implements IBuilderProcess {
+ private static final Set> ORIENTATION_PROPS =
+ ImmutableSet.of(
+ RotatedPillarBlock.AXIS, HorizontalDirectionalBlock.FACING,
+ StairBlock.FACING, StairBlock.HALF, StairBlock.SHAPE,
+ PipeBlock.NORTH, PipeBlock.EAST, PipeBlock.SOUTH, PipeBlock.WEST, PipeBlock.UP,
+ TrapDoorBlock.OPEN, TrapDoorBlock.HALF
+ );
+
private HashSet incorrectPositions;
private LongOpenHashSet observedCompleted; // positions that are completed even if they're out of render distance and we can't make sure right now
private String name;
@@ -110,6 +118,20 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
if (!Baritone.settings().buildSubstitutes.value.isEmpty()) {
this.schematic = new SubstituteSchematic(this.schematic, Baritone.settings().buildSubstitutes.value);
}
+ if (Baritone.settings().buildSchematicMirror.value != net.minecraft.world.level.block.Mirror.NONE) {
+ this.schematic = new MirroredSchematic(this.schematic, Baritone.settings().buildSchematicMirror.value);
+ }
+ if (Baritone.settings().buildSchematicRotation.value != net.minecraft.world.level.block.Rotation.NONE) {
+ this.schematic = new RotatedSchematic(this.schematic, Baritone.settings().buildSchematicRotation.value);
+ }
+ // TODO this preserves the old behavior, but maybe we should bake the setting value right here
+ this.schematic = new MaskSchematic(this.schematic) {
+ @Override
+ public boolean partOfMask(int x, int y, int z, BlockState current) {
+ // partOfMask is only called inside the schematic so desiredState is not null
+ return !Baritone.settings().buildSkipBlocks.value.contains(this.desiredState(x, y, z, current, Collections.emptyList()).getBlock());
+ }
+ };
int x = origin.getX();
int y = origin.getY();
int z = origin.getZ();
@@ -168,15 +190,15 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
if (!format.isPresent()) {
return false;
}
- ISchematic parsed;
+ IStaticSchematic parsed;
try {
parsed = format.get().parse(new FileInputStream(schematic));
} catch (Exception e) {
e.printStackTrace();
return false;
}
- parsed = applyMapArtAndSelection(origin, (IStaticSchematic) parsed);
- build(name, parsed, origin);
+ ISchematic schem = applyMapArtAndSelection(origin, parsed);
+ build(name, schem, origin);
return true;
}
@@ -196,17 +218,10 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
if (SchematicaHelper.isSchematicaPresent()) {
Optional> schematic = SchematicaHelper.getOpenSchematic();
if (schematic.isPresent()) {
- IStaticSchematic s = schematic.get().getA();
+ IStaticSchematic raw = schematic.get().getA();
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(
- schematic.get().getA().toString(),
- schem,
- origin
- );
+ ISchematic schem = applyMapArtAndSelection(origin, raw);
+ this.build(raw.toString(), schem, origin);
} else {
logDirect("No schematic currently open");
}
@@ -219,19 +234,13 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
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(NbtIo.readCompressed(Files.newInputStream(LitematicaHelper.getSchematicFile(i).toPath())), false);
- Vec3i correctedOrigin = LitematicaHelper.getCorrectedOrigin(schematic1, i);
- ISchematic schematic2 = LitematicaHelper.blackMagicFuckery(schematic1, i);
- schematic2 = applyMapArtAndSelection(origin, (IStaticSchematic) schematic2);
- build(name, schematic2, correctedOrigin);
- } catch (Exception e) {
- logDirect("Schematic File could not be loaded.");
- }
+ if (LitematicaHelper.hasLoadedSchematic(i)) {
+ Tuple schematic = LitematicaHelper.getSchematic(i);
+ Vec3i correctedOrigin = schematic.getB();
+ ISchematic schematic2 = applyMapArtAndSelection(correctedOrigin, schematic.getA());
+ build(schematic.getA().toString(), schematic2, correctedOrigin);
} else {
- logDirect("No schematic currently loaded");
+ logDirect(String.format("List of placements has no entry %s", i + 1));
}
} else {
logDirect("Litematica is not present");
@@ -362,7 +371,11 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
if (!placementPlausible(new BetterBlockPos(x, y, z), toPlace)) {
continue;
}
- AABB aabb = placeAgainstState.getShape(ctx.world(), placeAgainstPos).bounds();
+ VoxelShape shape = placeAgainstState.getShape(ctx.world(), placeAgainstPos);
+ if (shape.isEmpty()) {
+ continue;
+ }
+ AABB aabb = shape.bounds();
for (Vec3 placementMultiplier : aabbSideMultipliers(against)) {
double placeX = placeAgainstPos.x + aabb.minX * placementMultiplier.x + aabb.maxX * (1 - placementMultiplier.x);
double placeY = placeAgainstPos.y + aabb.minY * placementMultiplier.y + aabb.maxY * (1 - placementMultiplier.y);
@@ -429,7 +442,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
double z = side.getStepZ() == 0 ? 0.5 : (1 + side.getStepZ()) / 2D;
return new Vec3[]{new Vec3(x, 0.25, z), new Vec3(x, 0.75, z)};
default: // null
- throw new IllegalStateException();
+ throw new IllegalStateException("Unexpected side " + side);
}
}
@@ -438,8 +451,8 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
return onTick(calcFailed, isSafeToCancel, 0);
}
- public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel, int recursions) {
- if (recursions > 1000) { // onTick calls itself, don't crash
+ private PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel, int recursions) {
+ if (recursions > 100) { // onTick calls itself, don't crash
return new PathingCommand(null, PathingCommandType.SET_GOAL_AND_PATH);
}
approxPlaceable = approxPlaceable(36);
@@ -683,8 +696,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
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())) {
+ if (!observedCompleted.contains(BetterBlockPos.longHash(blockX, blockY, blockZ))) {
// and we've never seen this position be correct
// therefore mark as incorrect
incorrectPositions.add(new BetterBlockPos(blockX, blockY, blockZ));
@@ -707,13 +719,16 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
List sourceLiquids = new ArrayList<>();
List flowingLiquids = new ArrayList<>();
Map missing = new HashMap<>();
+ List outOfBounds = new ArrayList<>();
incorrectPositions.forEach(pos -> {
BlockState state = bcc.bsi.get0(pos);
if (state.getBlock() instanceof AirBlock) {
- if (containsBlockState(approxPlaceable, bcc.getSchematic(pos.x, pos.y, pos.z, state))) {
+ BlockState desired = bcc.getSchematic(pos.x, pos.y, pos.z, state);
+ if (desired == null) {
+ outOfBounds.add(pos);
+ } else if (containsBlockState(approxPlaceable, desired)) {
placeable.add(pos);
} else {
- BlockState desired = bcc.getSchematic(pos.x, pos.y, pos.z, state);
missing.put(desired, 1 + missing.getOrDefault(desired, 0));
}
} else {
@@ -731,6 +746,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
}
}
});
+ incorrectPositions.removeAll(outOfBounds);
List toBreak = new ArrayList<>();
breakable.forEach(pos -> toBreak.add(breakGoal(pos, bcc)));
List toPlace = new ArrayList<>();
@@ -983,6 +999,22 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
return paused ? "Builder Paused" : "Building " + name;
}
+ @Override
+ public Optional getMinLayer() {
+ if (Baritone.settings().buildInLayers.value) {
+ return Optional.of(this.layer);
+ }
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional getMaxLayer() {
+ if (Baritone.settings().buildInLayers.value) {
+ return Optional.of(this.stopAtHeight);
+ }
+ return Optional.empty();
+ }
+
private List approxPlaceable(int size) {
List result = new ArrayList<>();
for (int i = 0; i < size; i++) {
@@ -1009,15 +1041,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
return result;
}
- public static final Set> orientationProps =
- ImmutableSet.of(
- RotatedPillarBlock.AXIS, HorizontalDirectionalBlock.FACING,
- StairBlock.FACING, StairBlock.HALF, StairBlock.SHAPE,
- PipeBlock.NORTH, PipeBlock.EAST, PipeBlock.SOUTH, PipeBlock.WEST, PipeBlock.UP,
- TrapDoorBlock.OPEN, TrapDoorBlock.HALF
- );
-
- private boolean sameBlockstate(BlockState first, BlockState second) {
+ private static boolean sameBlockstate(BlockState first, BlockState second) {
if (first.getBlock() != second.getBlock()) {
return false;
}
@@ -1030,7 +1054,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
ImmutableMap, Comparable>> map2 = second.getValues();
for (Property> prop : map1.keySet()) {
if (map1.get(prop) != map2.get(prop)
- && !(ignoreDirection && orientationProps.contains(prop))
+ && !(ignoreDirection && ORIENTATION_PROPS.contains(prop))
&& !ignoredProps.contains(prop.getName())) {
return false;
}
@@ -1038,7 +1062,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
return true;
}
- private boolean containsBlockState(Collection states, BlockState state) {
+ private static boolean containsBlockState(Collection states, BlockState state) {
for (BlockState testee : states) {
if (sameBlockstate(testee, state)) {
return true;
@@ -1047,7 +1071,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
return false;
}
- private boolean valid(BlockState current, BlockState desired, boolean itemVerify) {
+ private static boolean valid(BlockState current, BlockState desired, boolean itemVerify) {
if (desired == null) {
return true;
}
@@ -1063,7 +1087,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
if (desired.getBlock() instanceof AirBlock && Baritone.settings().buildIgnoreBlocks.value.contains(current.getBlock())) {
return true;
}
- if (Baritone.settings().buildSkipBlocks.value.contains(desired.getBlock()) && !itemVerify) {
+ if (!(current.getBlock() instanceof AirBlock) && Baritone.settings().buildIgnoreExisting.value && !itemVerify) {
return true;
}
if (Baritone.settings().buildValidSubstitutes.value.getOrDefault(desired.getBlock(), Collections.emptyList()).contains(current.getBlock()) && !itemVerify) {
@@ -1109,12 +1133,12 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
return COST_INF;
}
BlockState sch = getSchematic(x, y, z, current);
- if (sch != null && !Baritone.settings().buildSkipBlocks.value.contains(sch.getBlock())) {
+ if (sch != null) {
// TODO this can return true even when allowPlace is off.... is that an issue?
if (sch.getBlock() instanceof AirBlock) {
// 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
+ return placeBlockCost * Baritone.settings().placeIncorrectBlockPenaltyMultiplier.value; // we're going to have to break it eventually
}
if (placeable.contains(sch)) {
return 0; // thats right we gonna make it FREE to place a block where it should go in a structure
@@ -1127,7 +1151,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
}
// we want it to be something that we don't have
// even more of a pain to place something wrong
- return placeBlockCost * 3;
+ return placeBlockCost * 1.5 * Baritone.settings().placeIncorrectBlockPenaltyMultiplier.value;
} else {
if (hasThrowaway) {
return placeBlockCost;
@@ -1143,7 +1167,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
return COST_INF;
}
BlockState sch = getSchematic(x, y, z, current);
- if (sch != null && !Baritone.settings().buildSkipBlocks.value.contains(sch.getBlock())) {
+ if (sch != null) {
if (sch.getBlock() instanceof AirBlock) {
// it should be air
// regardless of current contents, we can break it
diff --git a/src/main/java/baritone/process/CustomGoalProcess.java b/src/main/java/baritone/process/CustomGoalProcess.java
index d0dca9cbf..e101df74f 100644
--- a/src/main/java/baritone/process/CustomGoalProcess.java
+++ b/src/main/java/baritone/process/CustomGoalProcess.java
@@ -114,7 +114,7 @@ public final class CustomGoalProcess extends BaritoneProcessHelper implements IC
}
return new PathingCommand(this.goal, PathingCommandType.SET_GOAL_AND_PATH);
default:
- throw new IllegalStateException();
+ throw new IllegalStateException("Unexpected state " + this.state);
}
}
diff --git a/src/main/java/baritone/process/ElytraProcess.java b/src/main/java/baritone/process/ElytraProcess.java
index 8e34b9f9e..fcd6c4b34 100644
--- a/src/main/java/baritone/process/ElytraProcess.java
+++ b/src/main/java/baritone/process/ElytraProcess.java
@@ -69,15 +69,25 @@ public class ElytraProcess extends BaritoneProcessHelper implements IBaritonePro
private ElytraBehavior behavior;
private boolean predictingTerrain;
+ @Override
+ public void onLostControl() {
+ this.state = State.START_FLYING; // TODO: null state?
+ this.goingToLandingSpot = false;
+ this.landingSpot = null;
+ this.reachedGoal = false;
+ this.goal = null;
+ destroyBehaviorAsync();
+ }
+
private ElytraProcess(Baritone baritone) {
super(baritone);
baritone.getGameEventHandler().registerEventListener(this);
}
- public static T create(final Baritone baritone) {
- return (T) (NetherPathfinderContext.isSupported()
+ public static IElytraProcess create(final Baritone baritone) {
+ return NetherPathfinderContext.isSupported()
? new ElytraProcess(baritone)
- : new NullElytraProcess(baritone));
+ : new NullElytraProcess(baritone);
}
@Override
@@ -276,16 +286,6 @@ public class ElytraProcess extends BaritoneProcessHelper implements IBaritonePro
this.state = State.FLYING;
}
- @Override
- public void onLostControl() {
- this.goal = null;
- this.goingToLandingSpot = false;
- this.landingSpot = null;
- this.reachedGoal = false;
- this.state = State.START_FLYING; // TODO: null state?
- destroyBehaviorAsync();
- }
-
private void destroyBehaviorAsync() {
ElytraBehavior behavior = this.behavior;
if (behavior != null) {
diff --git a/src/main/java/baritone/process/ExploreProcess.java b/src/main/java/baritone/process/ExploreProcess.java
index 23fe7c23a..514a110e6 100644
--- a/src/main/java/baritone/process/ExploreProcess.java
+++ b/src/main/java/baritone/process/ExploreProcess.java
@@ -118,7 +118,9 @@ public final class ExploreProcess extends BaritoneProcessHelper implements IExpl
int dz = (mult * 2 - 1) * zval; // dz can be either -zval or zval
int trueDist = Math.abs(dx) + Math.abs(dz);
if (trueDist != dist) {
- throw new IllegalStateException();
+ throw new IllegalStateException(String.format(
+ "Offset %s %s has distance %s, expected %s",
+ dx, dz, trueDist, dist));
}
switch (filter.isAlreadyExplored(chunkX + dx, chunkZ + dz)) {
case UNKNOWN:
diff --git a/src/main/java/baritone/process/FarmProcess.java b/src/main/java/baritone/process/FarmProcess.java
index c453beff2..4bb4fa947 100644
--- a/src/main/java/baritone/process/FarmProcess.java
+++ b/src/main/java/baritone/process/FarmProcess.java
@@ -42,6 +42,7 @@ import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.AirBlock;
+import net.minecraft.world.level.block.BambooStalkBlock;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.BonemealableBlock;
@@ -95,6 +96,7 @@ public final class FarmProcess extends BaritoneProcessHelper implements IFarmPro
Items.NETHER_WART,
Items.COCOA_BEANS,
Blocks.SUGAR_CANE.asItem(),
+ Blocks.BAMBOO.asItem(),
Blocks.CACTUS.asItem()
);
@@ -137,6 +139,15 @@ public final class FarmProcess extends BaritoneProcessHelper implements IFarmPro
return true;
}
},
+ BAMBOO(Blocks.BAMBOO, null) {
+ @Override
+ public boolean readyToHarvest(Level world, BlockPos pos, BlockState state) {
+ if (Baritone.settings().replantCrops.value) {
+ return world.getBlockState(pos.below()).getBlock() instanceof BambooStalkBlock;
+ }
+ return true;
+ }
+ },
CACTUS(Blocks.CACTUS, null) {
@Override
public boolean readyToHarvest(Level world, BlockPos pos, BlockState state) {
@@ -191,20 +202,20 @@ public final class FarmProcess extends BaritoneProcessHelper implements IFarmPro
@Override
public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) {
- ArrayList scan = new ArrayList<>();
- for (Harvest harvest : Harvest.values()) {
- scan.add(harvest.block);
- }
- if (Baritone.settings().replantCrops.value) {
- scan.add(Blocks.FARMLAND);
- scan.add(Blocks.JUNGLE_LOG);
- if (Baritone.settings().replantNetherWart.value) {
- scan.add(Blocks.SOUL_SAND);
- }
- }
-
if (Baritone.settings().mineGoalUpdateInterval.value != 0 && tickCount++ % Baritone.settings().mineGoalUpdateInterval.value == 0) {
- Baritone.getExecutor().execute(() -> locations = BaritoneAPI.getProvider().getWorldScanner().scanChunkRadius(ctx, scan, 256, 10, 10));
+ ArrayList scan = new ArrayList<>();
+ for (Harvest harvest : Harvest.values()) {
+ scan.add(harvest.block);
+ }
+ if (Baritone.settings().replantCrops.value) {
+ scan.add(Blocks.FARMLAND);
+ scan.add(Blocks.JUNGLE_LOG);
+ if (Baritone.settings().replantNetherWart.value) {
+ scan.add(Blocks.SOUL_SAND);
+ }
+ }
+
+ Baritone.getExecutor().execute(() -> locations = BaritoneAPI.getProvider().getWorldScanner().scanChunkRadius(ctx, scan, Baritone.settings().farmMaxScanSize.value, 10, 10));
}
if (locations == null) {
return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE);
@@ -256,7 +267,12 @@ public final class FarmProcess extends BaritoneProcessHelper implements IFarmPro
}
baritone.getInputOverrideHandler().clearAllKeys();
+ BetterBlockPos playerPos = ctx.playerFeet();
+ double blockReachDistance = ctx.playerController().getBlockReachDistance();
for (BlockPos pos : toBreak) {
+ if (playerPos.distSqr(pos) > blockReachDistance * blockReachDistance) {
+ continue;
+ }
Optional rot = RotationUtils.reachable(ctx, pos);
if (rot.isPresent() && isSafeToCancel) {
baritone.getLookBehavior().updateTarget(rot.get(), true);
@@ -270,10 +286,13 @@ public final class FarmProcess extends BaritoneProcessHelper implements IFarmPro
ArrayList both = new ArrayList<>(openFarmland);
both.addAll(openSoulsand);
for (BlockPos pos : both) {
+ if (playerPos.distSqr(pos) > blockReachDistance * blockReachDistance) {
+ continue;
+ }
boolean soulsand = openSoulsand.contains(pos);
- Optional rot = RotationUtils.reachableOffset(ctx, pos, new Vec3(pos.getX() + 0.5, pos.getY() + 1, pos.getZ() + 0.5), ctx.playerController().getBlockReachDistance(), false);
+ Optional rot = RotationUtils.reachableOffset(ctx, pos, new Vec3(pos.getX() + 0.5, pos.getY() + 1, pos.getZ() + 0.5), blockReachDistance, false);
if (rot.isPresent() && isSafeToCancel && baritone.getInventoryBehavior().throwaway(true, soulsand ? this::isNetherWart : this::isPlantable)) {
- HitResult result = RayTraceUtils.rayTraceTowards(ctx.player(), rot.get(), ctx.playerController().getBlockReachDistance());
+ HitResult result = RayTraceUtils.rayTraceTowards(ctx.player(), rot.get(), blockReachDistance);
if (result instanceof BlockHitResult && ((BlockHitResult) result).getDirection() == Direction.UP) {
baritone.getLookBehavior().updateTarget(rot.get(), true);
if (ctx.isLookingAt(pos)) {
@@ -284,14 +303,17 @@ public final class FarmProcess extends BaritoneProcessHelper implements IFarmPro
}
}
for (BlockPos pos : openLog) {
+ if (playerPos.distSqr(pos) > blockReachDistance * blockReachDistance) {
+ continue;
+ }
for (Direction dir : Direction.Plane.HORIZONTAL) {
if (!(ctx.world().getBlockState(pos.relative(dir)).getBlock() instanceof AirBlock)) {
continue;
}
Vec3 faceCenter = Vec3.atCenterOf(pos).add(Vec3.atLowerCornerOf(dir.getNormal()).scale(0.5));
- Optional rot = RotationUtils.reachableOffset(ctx, pos, faceCenter, ctx.playerController().getBlockReachDistance(), false);
+ Optional rot = RotationUtils.reachableOffset(ctx, pos, faceCenter, blockReachDistance, false);
if (rot.isPresent() && isSafeToCancel && baritone.getInventoryBehavior().throwaway(true, this::isCocoa)) {
- HitResult result = RayTraceUtils.rayTraceTowards(ctx.player(), rot.get(), ctx.playerController().getBlockReachDistance());
+ HitResult result = RayTraceUtils.rayTraceTowards(ctx.player(), rot.get(), blockReachDistance);
if (result instanceof BlockHitResult && ((BlockHitResult) result).getDirection() == dir) {
baritone.getLookBehavior().updateTarget(rot.get(), true);
if (ctx.isLookingAt(pos)) {
@@ -303,6 +325,9 @@ public final class FarmProcess extends BaritoneProcessHelper implements IFarmPro
}
}
for (BlockPos pos : bonemealable) {
+ if (playerPos.distSqr(pos) > blockReachDistance * blockReachDistance) {
+ continue;
+ }
Optional rot = RotationUtils.reachable(ctx, pos);
if (rot.isPresent() && isSafeToCancel && baritone.getInventoryBehavior().throwaway(true, this::isBoneMeal)) {
baritone.getLookBehavior().updateTarget(rot.get(), true);
@@ -359,6 +384,14 @@ public final class FarmProcess extends BaritoneProcessHelper implements IFarmPro
}
}
}
+ if (goalz.isEmpty()) {
+ logDirect("Farm failed");
+ if (Baritone.settings().notificationOnFarmFail.value) {
+ logNotification("Farm failed", true);
+ }
+ onLostControl();
+ return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE);
+ }
return new PathingCommand(new GoalComposite(goalz.toArray(new Goal[0])), PathingCommandType.SET_GOAL_AND_PATH);
}
diff --git a/src/main/java/baritone/process/FollowProcess.java b/src/main/java/baritone/process/FollowProcess.java
index b123216a6..0be7a4e80 100644
--- a/src/main/java/baritone/process/FollowProcess.java
+++ b/src/main/java/baritone/process/FollowProcess.java
@@ -19,6 +19,7 @@ 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.GoalNear;
import baritone.api.pathing.goals.GoalXZ;
@@ -27,11 +28,14 @@ import baritone.api.process.PathingCommand;
import baritone.api.process.PathingCommandType;
import baritone.api.utils.BetterBlockPos;
import baritone.utils.BaritoneProcessHelper;
+import net.minecraft.core.BlockPos;
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.item.ItemEntity;
+import net.minecraft.world.item.ItemStack;
+
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
-import net.minecraft.core.BlockPos;
-import net.minecraft.world.entity.Entity;
/**
* Follow an entity
@@ -42,6 +46,7 @@ public final class FollowProcess extends BaritoneProcessHelper implements IFollo
private Predicate filter;
private List cache;
+ private boolean into; // walk straight into the target, regardless of settings
public FollowProcess(Baritone baritone) {
super(baritone);
@@ -56,12 +61,15 @@ public final class FollowProcess extends BaritoneProcessHelper implements IFollo
private Goal towards(Entity following) {
BlockPos pos;
- if (Baritone.settings().followOffsetDistance.value == 0) {
+ if (Baritone.settings().followOffsetDistance.value == 0 || into) {
pos = following.blockPosition();
} else {
GoalXZ g = GoalXZ.fromDirection(following.position(), Baritone.settings().followOffsetDirection.value, Baritone.settings().followOffsetDistance.value);
pos = new BetterBlockPos(g.getX(), following.position().y, g.getZ());
}
+ if (into) {
+ return new GoalBlock(pos);
+ }
return new GoalNear(pos, Baritone.settings().followRadius.value);
}
@@ -76,6 +84,10 @@ public final class FollowProcess extends BaritoneProcessHelper implements IFollo
if (entity.equals(ctx.player())) {
return false;
}
+ int maxDist = Baritone.settings().followTargetMaxDistance.value;
+ if (maxDist != 0 && entity.distanceToSqr(ctx.player()) > maxDist * maxDist) {
+ return false;
+ }
return ctx.entitiesStream().anyMatch(entity::equals);
}
@@ -110,6 +122,13 @@ public final class FollowProcess extends BaritoneProcessHelper implements IFollo
@Override
public void follow(Predicate filter) {
this.filter = filter;
+ this.into = false;
+ }
+
+ @Override
+ public void pickup(Predicate filter) {
+ this.filter = e -> e instanceof ItemEntity && filter.test(((ItemEntity) e).getItem());
+ this.into = true;
}
@Override
diff --git a/src/main/java/baritone/process/MineProcess.java b/src/main/java/baritone/process/MineProcess.java
index 852e6ba3d..9a7a18f49 100644
--- a/src/main/java/baritone/process/MineProcess.java
+++ b/src/main/java/baritone/process/MineProcess.java
@@ -53,8 +53,6 @@ import static baritone.api.pathing.movement.ActionCosts.COST_INF;
*/
public final class MineProcess extends BaritoneProcessHelper implements IMineProcess {
- private static final int ORE_LOCATIONS_COUNT = 64;
-
private BlockOptionalMetaLookup filter;
private List knownOreLocations;
private List blacklist; // inaccessible
@@ -79,7 +77,6 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro
int curr = ctx.player().getInventory().items.stream()
.filter(stack -> filter.has(stack))
.mapToInt(ItemStack::getCount).sum();
- System.out.println("Currently have " + curr + " valid items");
if (curr >= desiredQuantity) {
logDirect("Have " + curr + " valid items");
cancel();
@@ -121,7 +118,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro
.filter(pos -> pos.getX() == ctx.playerFeet().getX() && pos.getZ() == ctx.playerFeet().getZ())
.filter(pos -> pos.getY() >= ctx.playerFeet().getY())
.filter(pos -> !(BlockStateInterface.get(ctx, pos).getBlock() instanceof AirBlock)) // after breaking a block, it takes mineGoalUpdateInterval ticks for it to actually update this list =(
- .min(Comparator.comparingDouble(ctx.playerFeet()::distSqr));
+ .min(Comparator.comparingDouble(ctx.playerFeet().above()::distSqr));
baritone.getInputOverrideHandler().clearAllKeys();
if (shaft.isPresent() && ctx.player().onGround()) {
BlockPos pos = shaft.get();
@@ -186,7 +183,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro
List locs = knownOreLocations;
if (!locs.isEmpty()) {
CalculationContext context = new CalculationContext(baritone);
- List locs2 = prune(context, new ArrayList<>(locs), filter, ORE_LOCATIONS_COUNT, blacklist, droppedItemsScan());
+ List locs2 = prune(context, new ArrayList<>(locs), filter, Baritone.settings().mineMaxOreLocationsCount.value, blacklist, droppedItemsScan());
// can't reassign locs, gotta make a new var locs2, because we use it in a lambda right here, and variables you use in a lambda must be effectively final
Goal goal = new GoalComposite(locs2.stream().map(loc -> coalesce(loc, locs2, context)).toArray(Goal[]::new));
knownOreLocations = locs2;
@@ -235,7 +232,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro
return;
}
List dropped = droppedItemsScan();
- List locs = searchWorld(context, filter, ORE_LOCATIONS_COUNT, already, blacklist, dropped);
+ List locs = searchWorld(context, filter, Baritone.settings().mineMaxOreLocationsCount.value, already, blacklist, dropped);
locs.addAll(dropped);
if (locs.isEmpty() && !Baritone.settings().exploreForBlocks.value) {
logDirect("No locations for " + filter + " known, cancelling");
@@ -425,7 +422,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro
}
}
}
- knownOreLocations = prune(new CalculationContext(baritone), knownOreLocations, filter, ORE_LOCATIONS_COUNT, blacklist, dropped);
+ knownOreLocations = prune(new CalculationContext(baritone), knownOreLocations, filter, Baritone.settings().mineMaxOreLocationsCount.value, blacklist, dropped);
return true;
}
@@ -488,7 +485,11 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro
public static boolean plausibleToBreak(CalculationContext ctx, BlockPos pos) {
- if (MovementHelper.getMiningDurationTicks(ctx, pos.getX(), pos.getY(), pos.getZ(), ctx.bsi.get0(pos), true) >= COST_INF) {
+ BlockState state = ctx.bsi.get0(pos);
+ if (MovementHelper.getMiningDurationTicks(ctx, pos.getX(), pos.getY(), pos.getZ(), state, true) >= COST_INF) {
+ return false;
+ }
+ if (MovementHelper.avoidBreaking(ctx.bsi, pos.getX(), pos.getY(), pos.getZ(), state)) {
return false;
}
diff --git a/src/main/java/baritone/process/elytra/ElytraBehavior.java b/src/main/java/baritone/process/elytra/ElytraBehavior.java
index 1c9ca9a33..8cdfd0e39 100644
--- a/src/main/java/baritone/process/elytra/ElytraBehavior.java
+++ b/src/main/java/baritone/process/elytra/ElytraBehavior.java
@@ -176,9 +176,9 @@ public final class ElytraBehavior implements Helper {
.thenRun(() -> {
final double distance = this.path.get(0).distanceTo(this.path.get(this.path.size() - 1));
if (this.completePath) {
- logDirect(String.format("Computed path (%.1f blocks in %.4f seconds)", distance, (System.nanoTime() - start) / 1e9d));
+ logVerbose(String.format("Computed path (%.1f blocks in %.4f seconds)", distance, (System.nanoTime() - start) / 1e9d));
} else {
- logDirect(String.format("Computed segment (Next %.1f blocks in %.4f seconds)", distance, (System.nanoTime() - start) / 1e9d));
+ logVerbose(String.format("Computed segment (Next %.1f blocks in %.4f seconds)", distance, (System.nanoTime() - start) / 1e9d));
}
})
.whenComplete((result, ex) -> {
@@ -233,9 +233,9 @@ public final class ElytraBehavior implements Helper {
final double distance = this.path.get(0).distanceTo(this.path.get(recompute));
if (this.completePath) {
- logDirect(String.format("Computed path (%.1f blocks in %.4f seconds)", distance, (System.nanoTime() - start) / 1e9d));
+ logVerbose(String.format("Computed path (%.1f blocks in %.4f seconds)", distance, (System.nanoTime() - start) / 1e9d));
} else {
- logDirect(String.format("Computed segment (Next %.1f blocks in %.4f seconds)", distance, (System.nanoTime() - start) / 1e9d));
+ logVerbose(String.format("Computed segment (Next %.1f blocks in %.4f seconds)", distance, (System.nanoTime() - start) / 1e9d));
}
})
.whenComplete((result, ex) -> {
@@ -245,7 +245,7 @@ public final class ElytraBehavior implements Helper {
if (cause instanceof PathCalculationException) {
logDirect("Failed to compute next segment");
if (ctx.player().distanceToSqr(pathStart.getCenter()) < 16 * 16) {
- logDirect("Player is near the segment start, therefore repeating this calculation is pointless. Marking as complete");
+ logVerbose("Player is near the segment start, therefore repeating this calculation is pointless. Marking as complete");
completePath = true;
}
} else {
@@ -323,7 +323,7 @@ public final class ElytraBehavior implements Helper {
if (ElytraBehavior.this.process.state != ElytraProcess.State.LANDING && this.ticksNearUnchanged > 100) {
this.pathRecalcSegment(OptionalInt.of(rangeEndExcl - 1))
.thenRun(() -> {
- logDirect("Recalculating segment, no progress in last 100 ticks");
+ logVerbose("Recalculating segment, no progress in last 100 ticks");
});
this.ticksNearUnchanged = 0;
return;
@@ -350,7 +350,7 @@ public final class ElytraBehavior implements Helper {
final long start = System.nanoTime();
this.pathRecalcSegment(rejoinMainPathAt)
.thenRun(() -> {
- logDirect(String.format("Recalculated segment around path blockage near %s %s %s (next %.1f blocks in %.4f seconds)",
+ logVerbose(String.format("Recalculated segment around path blockage near %s %s %s (next %.1f blocks in %.4f seconds)",
SettingsUtil.maybeCensor(blockage.x),
SettingsUtil.maybeCensor(blockage.y),
SettingsUtil.maybeCensor(blockage.z),
@@ -362,7 +362,7 @@ public final class ElytraBehavior implements Helper {
}
}
if (!canSeeAny && rangeStartIncl < rangeEndExcl - 2 && process.state != ElytraProcess.State.GET_TO_JUMP) {
- this.pathRecalcSegment(OptionalInt.of(rangeEndExcl - 1)).thenRun(() -> logDirect("Recalculated segment since no path points were visible"));
+ this.pathRecalcSegment(OptionalInt.of(rangeEndExcl - 1)).thenRun(() -> logVerbose("Recalculated segment since no path points were visible"));
}
}
@@ -583,10 +583,10 @@ public final class ElytraBehavior implements Helper {
trySwapElytra();
if (ctx.player().horizontalCollision) {
- logDirect("hbonk");
+ logVerbose("hbonk");
}
if (ctx.player().verticalCollision) {
- logDirect("vbonk");
+ logVerbose("vbonk");
}
final SolverContext solverContext = this.new SolverContext(false);
@@ -611,14 +611,14 @@ public final class ElytraBehavior implements Helper {
}
if (solution == null) {
- logDirect("no solution");
+ logVerbose("no solution");
return;
}
baritone.getLookBehavior().updateTarget(solution.rotation, false);
if (!solution.solvedPitch) {
- logDirect("no pitch solution, probably gonna crash in a few ticks LOL!!!");
+ logVerbose("no pitch solution, probably gonna crash in a few ticks LOL!!!");
return;
} else {
this.aimPos = new BetterBlockPos(solution.goingTo.x, solution.goingTo.y, solution.goingTo.z);
@@ -760,7 +760,7 @@ public final class ElytraBehavior implements Helper {
logDirect("no fireworks");
return;
}
- logDirect("attempting to use firework" + (forceUseFirework ? " (forced)" : ""));
+ logVerbose("attempting to use firework" + (forceUseFirework ? " (forced)" : ""));
ctx.playerController().processRightClick(ctx.player(), ctx.world(), InteractionHand.MAIN_HAND);
this.minimumBoostTicks = 10 * (1 + getFireworkBoost(ctx.player().getItemInHand(InteractionHand.MAIN_HAND)).orElse(0));
this.remainingFireworkTicks = 10;
@@ -1319,4 +1319,10 @@ public final class ElytraBehavior implements Helper {
queueWindowClick(ctx.player().inventoryMenu.containerId, slotId, 0, ClickType.PICKUP);
}
}
+
+ void logVerbose(String message) {
+ if (Baritone.settings().elytraChatSpam.value) {
+ logDebug(message);
+ }
+ }
}
diff --git a/src/main/java/baritone/utils/BlockBreakHelper.java b/src/main/java/baritone/utils/BlockBreakHelper.java
index 2d209c721..0c5cf6f00 100644
--- a/src/main/java/baritone/utils/BlockBreakHelper.java
+++ b/src/main/java/baritone/utils/BlockBreakHelper.java
@@ -17,7 +17,9 @@
package baritone.utils;
+import baritone.api.BaritoneAPI;
import baritone.api.utils.IPlayerContext;
+import baritone.utils.accessor.IPlayerControllerMP;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult;
@@ -27,9 +29,12 @@ import net.minecraft.world.phys.HitResult;
* @since 8/25/2018
*/
public final class BlockBreakHelper {
+ // base ticks between block breaks caused by tick logic
+ private static final int BASE_BREAK_DELAY = 1;
private final IPlayerContext ctx;
- private boolean didBreakLastTick;
+ private boolean wasHitting;
+ private int breakDelayTimer = 0;
BlockBreakHelper(IPlayerContext ctx) {
this.ctx = ctx;
@@ -37,38 +42,46 @@ public final class BlockBreakHelper {
public void stopBreakingBlock() {
// The player controller will never be null, but the player can be
- if (ctx.player() != null && didBreakLastTick) {
- if (!ctx.playerController().hasBrokenBlock()) {
- // insane bypass to check breaking succeeded
- ctx.playerController().setHittingBlock(true);
- }
+ if (ctx.player() != null && wasHitting) {
+ ctx.playerController().setHittingBlock(false);
ctx.playerController().resetBlockRemoving();
- didBreakLastTick = false;
+ wasHitting = false;
}
}
public void tick(boolean isLeftClick) {
+ if (breakDelayTimer > 0) {
+ breakDelayTimer--;
+ return;
+ }
HitResult trace = ctx.objectMouseOver();
boolean isBlockTrace = trace != null && trace.getType() == HitResult.Type.BLOCK;
if (isLeftClick && isBlockTrace) {
- if (!didBreakLastTick) {
+ ctx.playerController().setHittingBlock(wasHitting);
+ if (ctx.playerController().hasBrokenBlock()) {
ctx.playerController().syncHeldItem();
ctx.playerController().clickBlock(((BlockHitResult) trace).getBlockPos(), ((BlockHitResult) trace).getDirection());
ctx.player().swing(InteractionHand.MAIN_HAND);
+ } else {
+ if (ctx.playerController().onPlayerDamageBlock(((BlockHitResult) trace).getBlockPos(), ((BlockHitResult) trace).getDirection())) {
+ ctx.player().swing(InteractionHand.MAIN_HAND);
+ }
+ if (ctx.playerController().hasBrokenBlock()) { // block broken this tick
+ // break delay timer only applies for multi-tick block breaks like vanilla
+ breakDelayTimer = BaritoneAPI.getSettings().blockBreakSpeed.value - BASE_BREAK_DELAY;
+ // must reset controller's destroy delay to prevent the client from delaying itself unnecessarily
+ ((IPlayerControllerMP) ctx.minecraft().gameMode).setDestroyDelay(0);
+ }
}
-
- // Attempt to break the block
- if (ctx.playerController().onPlayerDamageBlock(((BlockHitResult) trace).getBlockPos(), ((BlockHitResult) trace).getDirection())) {
- ctx.player().swing(InteractionHand.MAIN_HAND);
- }
-
+ // if true, we're breaking a block. if false, we broke the block this tick
+ wasHitting = !ctx.playerController().hasBrokenBlock();
+ // this value will be reset by the MC client handling mouse keys
+ // since we're not spoofing the click keybind to the client, the client will stop the break if isDestroyingBlock is true
+ // we store and restore this value on the next tick to determine if we're breaking a block
ctx.playerController().setHittingBlock(false);
-
- didBreakLastTick = true;
- } else if (didBreakLastTick) {
- stopBreakingBlock();
- didBreakLastTick = false;
+ } else {
+ wasHitting = false;
}
}
}
diff --git a/src/main/java/baritone/utils/BlockPlaceHelper.java b/src/main/java/baritone/utils/BlockPlaceHelper.java
index 93b0c4408..ca8d50523 100644
--- a/src/main/java/baritone/utils/BlockPlaceHelper.java
+++ b/src/main/java/baritone/utils/BlockPlaceHelper.java
@@ -25,6 +25,8 @@ import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult;
public class BlockPlaceHelper {
+ // base ticks between places caused by tick logic
+ private static final int BASE_PLACE_DELAY = 1;
private final IPlayerContext ctx;
private int rightClickTimer;
@@ -42,7 +44,7 @@ public class BlockPlaceHelper {
if (!rightClickRequested || ctx.player().isHandsBusy() || mouseOver == null || mouseOver.getType() != HitResult.Type.BLOCK) {
return;
}
- rightClickTimer = Baritone.settings().rightClickSpeed.value;
+ rightClickTimer = Baritone.settings().rightClickSpeed.value - BASE_PLACE_DELAY;
for (InteractionHand hand : InteractionHand.values()) {
if (ctx.playerController().processRightClickBlock(ctx.player(), ctx.world(), hand, (BlockHitResult) mouseOver) == InteractionResult.SUCCESS) {
ctx.player().swing(hand);
diff --git a/src/main/java/baritone/utils/BlockStateInterface.java b/src/main/java/baritone/utils/BlockStateInterface.java
index 2931b9392..19a0da57a 100644
--- a/src/main/java/baritone/utils/BlockStateInterface.java
+++ b/src/main/java/baritone/utils/BlockStateInterface.java
@@ -70,7 +70,7 @@ public class BlockStateInterface {
}
this.useTheRealWorld = !Baritone.settings().pathThroughCachedOnly.value;
if (!ctx.minecraft().isSameThread()) {
- throw new IllegalStateException();
+ throw new IllegalStateException("BlockStateInterface must be constructed on the main thread");
}
this.isPassableBlockPos = new BlockPos.MutableBlockPos();
this.access = new BlockStateInterfaceAccessWrapper(this);
@@ -132,7 +132,7 @@ public class BlockStateInterface {
prevCached = region;
cached = region;
}
- BlockState type = cached.getBlock(x & 511, y, z & 511);
+ BlockState type = cached.getBlock(x & 511, y + world.dimensionType().minY(), z & 511);
if (type == null) {
return AIR;
}
diff --git a/src/main/java/baritone/utils/GuiClick.java b/src/main/java/baritone/utils/GuiClick.java
index 113450d1c..48781e389 100644
--- a/src/main/java/baritone/utils/GuiClick.java
+++ b/src/main/java/baritone/utils/GuiClick.java
@@ -74,13 +74,11 @@ public class GuiClick extends Screen implements Helper {
Vec3 far = toWorld(mx, my, 1); // "Use 0.945 that's what stack overflow says" - leijurv
if (near != null && far != null) {
- ///
Vec3 viewerPos = new Vec3(PathRenderer.posX(), PathRenderer.posY(), PathRenderer.posZ());
LocalPlayer player = BaritoneAPI.getProvider().getPrimaryBaritone().getPlayerContext().player();
HitResult result = player.level().clip(new ClipContext(near.add(viewerPos), far.add(viewerPos), ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, player));
if (result != null && result.getType() == HitResult.Type.BLOCK) {
currentMouseOver = ((BlockHitResult) result).getBlockPos();
- System.out.println("currentMouseOver = " + currentMouseOver);
}
}
}
diff --git a/src/main/java/baritone/utils/PathingControlManager.java b/src/main/java/baritone/utils/PathingControlManager.java
index 3566cd23a..2205d62e7 100644
--- a/src/main/java/baritone/utils/PathingControlManager.java
+++ b/src/main/java/baritone/utils/PathingControlManager.java
@@ -68,7 +68,7 @@ public class PathingControlManager implements IPathingControlManager {
for (IBaritoneProcess proc : processes) {
proc.onLostControl();
if (proc.isActive() && !proc.isTemporary()) { // it's okay only for a temporary thing (like combat pause) to maintain control even if you say to cancel
- throw new IllegalStateException(proc.displayName());
+ throw new IllegalStateException(proc.displayName() + " stayed active after being cancelled");
}
}
}
@@ -121,7 +121,7 @@ public class PathingControlManager implements IPathingControlManager {
}
break;
default:
- throw new IllegalStateException();
+ throw new IllegalStateException("Unexpected command type " + command.commandType);
}
}
diff --git a/src/main/java/baritone/utils/ToolSet.java b/src/main/java/baritone/utils/ToolSet.java
index 38b1fafdd..ed4b166cf 100644
--- a/src/main/java/baritone/utils/ToolSet.java
+++ b/src/main/java/baritone/utils/ToolSet.java
@@ -177,7 +177,13 @@ public class ToolSet {
* @return how long it would take in ticks
*/
public static double calculateSpeedVsBlock(ItemStack item, BlockState state) {
- float hardness = state.getDestroySpeed(null, null);
+ float hardness;
+ try {
+ hardness = state.getDestroySpeed(null, null);
+ } catch (NullPointerException npe) {
+ // can't easily determine the hardness so treat it as unbreakable
+ return -1;
+ }
if (hardness < 0) {
return -1;
}
diff --git a/src/main/java/baritone/utils/accessor/IPlayerControllerMP.java b/src/main/java/baritone/utils/accessor/IPlayerControllerMP.java
index 72e6f7ee3..55fa43316 100644
--- a/src/main/java/baritone/utils/accessor/IPlayerControllerMP.java
+++ b/src/main/java/baritone/utils/accessor/IPlayerControllerMP.java
@@ -23,7 +23,11 @@ public interface IPlayerControllerMP {
void setIsHittingBlock(boolean isHittingBlock);
+ boolean isHittingBlock();
+
BlockPos getCurrentBlock();
void callSyncCurrentPlayItem();
+
+ void setDestroyDelay(int destroyDelay);
}
diff --git a/src/main/java/baritone/utils/player/BaritonePlayerController.java b/src/main/java/baritone/utils/player/BaritonePlayerController.java
index 42ba49052..b7e729b70 100644
--- a/src/main/java/baritone/utils/player/BaritonePlayerController.java
+++ b/src/main/java/baritone/utils/player/BaritonePlayerController.java
@@ -20,7 +20,6 @@ package baritone.utils.player;
import baritone.api.utils.IPlayerController;
import baritone.utils.accessor.IPlayerControllerMP;
import net.minecraft.client.Minecraft;
-import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
@@ -54,7 +53,7 @@ public final class BaritonePlayerController implements IPlayerController {
@Override
public boolean hasBrokenBlock() {
- return ((IPlayerControllerMP) mc.gameMode).getCurrentBlock().getY() == -1;
+ return !((IPlayerControllerMP) mc.gameMode).isHittingBlock();
}
@Override
diff --git a/src/main/java/baritone/utils/schematic/MapArtSchematic.java b/src/main/java/baritone/utils/schematic/MapArtSchematic.java
index 4f71aea64..723be3983 100644
--- a/src/main/java/baritone/utils/schematic/MapArtSchematic.java
+++ b/src/main/java/baritone/utils/schematic/MapArtSchematic.java
@@ -41,6 +41,7 @@ public class MapArtSchematic extends MaskSchematic {
private static int[][] generateHeightMap(IStaticSchematic schematic) {
int[][] heightMap = new int[schematic.widthX()][schematic.lengthZ()];
+ int missingColumns = 0;
for (int x = 0; x < schematic.widthX(); x++) {
for (int z = 0; z < schematic.lengthZ(); z++) {
BlockState[] column = schematic.getColumn(x, z);
@@ -48,12 +49,14 @@ public class MapArtSchematic extends MaskSchematic {
if (lowestBlockY.isPresent()) {
heightMap[x][z] = lowestBlockY.getAsInt();
} else {
- System.out.println("Column " + x + "," + z + " has no blocks, but it's apparently map art? wtf");
- System.out.println("Letting it be whatever");
- heightMap[x][z] = 256;
+ missingColumns++;
+ heightMap[x][z] = Integer.MAX_VALUE;
}
}
}
+ if (missingColumns != 0) {
+ System.out.println(missingColumns + " columns had no block despite being in a map art, letting them be whatever");
+ }
return heightMap;
}
diff --git a/src/main/java/baritone/utils/schematic/SchematicSystem.java b/src/main/java/baritone/utils/schematic/SchematicSystem.java
index 8afafa8c3..ec6e7f626 100644
--- a/src/main/java/baritone/utils/schematic/SchematicSystem.java
+++ b/src/main/java/baritone/utils/schematic/SchematicSystem.java
@@ -24,6 +24,7 @@ import baritone.utils.schematic.format.DefaultSchematicFormats;
import java.io.File;
import java.util.Arrays;
+import java.util.List;
import java.util.Optional;
/**
@@ -48,4 +49,9 @@ public enum SchematicSystem implements ISchematicSystem {
public Optional getByFile(File file) {
return this.registry.stream().filter(format -> format.isFileType(file)).findFirst();
}
+
+ @Override
+ public List getFileExtensions() {
+ return this.registry.stream().map(ISchematicFormat::getFileExtensions).flatMap(List::stream).toList();
+ }
}
diff --git a/src/main/java/baritone/utils/schematic/StaticSchematic.java b/src/main/java/baritone/utils/schematic/StaticSchematic.java
index 5a110281b..0c875c724 100644
--- a/src/main/java/baritone/utils/schematic/StaticSchematic.java
+++ b/src/main/java/baritone/utils/schematic/StaticSchematic.java
@@ -32,6 +32,16 @@ public class StaticSchematic extends AbstractSchematic implements IStaticSchemat
protected BlockState[][][] states;
+ public StaticSchematic() {}
+
+ public StaticSchematic(BlockState[][][] states) {
+ this.states = states;
+ boolean empty = states.length == 0 || states[0].length == 0 || states[0][0].length == 0;
+ this.x = empty ? 0 : states.length;
+ this.z = empty ? 0 : states[0].length;
+ this.y = empty ? 0 : states[0][0].length;
+ }
+
@Override
public BlockState desiredState(int x, int y, int z, BlockState current, List approxPlaceable) {
return this.states[x][z][y];
diff --git a/src/main/java/baritone/utils/schematic/format/DefaultSchematicFormats.java b/src/main/java/baritone/utils/schematic/format/DefaultSchematicFormats.java
index 17fafc821..25ef7b0d9 100644
--- a/src/main/java/baritone/utils/schematic/format/DefaultSchematicFormats.java
+++ b/src/main/java/baritone/utils/schematic/format/DefaultSchematicFormats.java
@@ -22,13 +22,15 @@ import baritone.api.schematic.format.ISchematicFormat;
import baritone.utils.schematic.format.defaults.LitematicaSchematic;
import baritone.utils.schematic.format.defaults.MCEditSchematic;
import baritone.utils.schematic.format.defaults.SpongeSchematic;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.nbt.NbtIo;
import org.apache.commons.io.FilenameUtils;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
-import net.minecraft.nbt.CompoundTag;
-import net.minecraft.nbt.NbtIo;
+import java.util.Collections;
+import java.util.List;
/**
* Default implementations of {@link ISchematicFormat}
@@ -81,7 +83,7 @@ public enum DefaultSchematicFormats implements ISchematicFormat {
case 5: //1.13-1.17
throw new UnsupportedOperationException("This litematic Version is too old.");
case 6: //1.18+
- return new LitematicaSchematic(nbt, false);
+ return new LitematicaSchematic(nbt);
default:
throw new UnsupportedOperationException("Unsuported Version of a Litematica Schematic");
}
@@ -98,4 +100,9 @@ public enum DefaultSchematicFormats implements ISchematicFormat {
public boolean isFileType(File file) {
return this.extension.equalsIgnoreCase(FilenameUtils.getExtension(file.getAbsolutePath()));
}
+
+ @Override
+ public List getFileExtensions() {
+ return Collections.singletonList(this.extension);
+ }
}
diff --git a/src/main/java/baritone/utils/schematic/format/defaults/LitematicaSchematic.java b/src/main/java/baritone/utils/schematic/format/defaults/LitematicaSchematic.java
index 65cdec058..89684981e 100644
--- a/src/main/java/baritone/utils/schematic/format/defaults/LitematicaSchematic.java
+++ b/src/main/java/baritone/utils/schematic/format/defaults/LitematicaSchematic.java
@@ -17,8 +17,9 @@
package baritone.utils.schematic.format.defaults;
+import baritone.api.schematic.CompositeSchematic;
+import baritone.api.schematic.IStaticSchematic;
import baritone.utils.schematic.StaticSchematic;
-import net.minecraft.core.Registry;
import net.minecraft.core.Vec3i;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.CompoundTag;
@@ -30,6 +31,7 @@ import net.minecraft.world.level.block.state.properties.Property;
import org.apache.commons.lang3.Validate;
import javax.annotation.Nullable;
+import java.util.Collections;
import java.util.Optional;
/**
@@ -39,35 +41,24 @@ import java.util.Optional;
* @author rycbar
* @since 22.09.2022
*/
-public final class LitematicaSchematic extends StaticSchematic {
- private final Vec3i offsetMinCorner;
- private final CompoundTag nbt;
+public final class LitematicaSchematic extends CompositeSchematic implements IStaticSchematic {
/**
* @param nbtTagCompound a decompressed file stream aka nbt data.
* @param rotated if the schematic is rotated by 90°.
*/
- public LitematicaSchematic(CompoundTag nbtTagCompound, boolean rotated) {
- this.nbt = nbtTagCompound;
- this.offsetMinCorner = new Vec3i(getMinOfSchematic("x"), getMinOfSchematic("y"), getMinOfSchematic("z"));
- this.y = Math.abs(nbt.getCompound("Metadata").getCompound("EnclosingSize").getInt("y"));
-
- if (rotated) {
- this.x = Math.abs(nbt.getCompound("Metadata").getCompound("EnclosingSize").getInt("z"));
- this.z = Math.abs(nbt.getCompound("Metadata").getCompound("EnclosingSize").getInt("x"));
- } else {
- this.x = Math.abs(nbt.getCompound("Metadata").getCompound("EnclosingSize").getInt("x"));
- this.z = Math.abs(nbt.getCompound("Metadata").getCompound("EnclosingSize").getInt("z"));
- }
- this.states = new BlockState[this.x][this.z][this.y];
- fillInSchematic();
+ public LitematicaSchematic(CompoundTag nbt) {
+ super(0, 0, 0);
+ fillInSchematic(nbt);
}
/**
- * @return Array of subregion names.
+ * @return Array of subregion tags.
*/
- private static String[] getRegions(CompoundTag nbt) {
- return nbt.getCompound("Regions").getAllKeys().toArray(new String[0]);
+ private static CompoundTag[] getRegions(CompoundTag nbt) {
+ return nbt.getCompound("Regions").getAllKeys().stream()
+ .map(nbt.getCompound("Regions")::getCompound)
+ .toArray(CompoundTag[]::new);
}
/**
@@ -76,14 +67,10 @@ public final class LitematicaSchematic extends StaticSchematic {
* @param s axis that should be read.
* @return the lower coord of the requested axis.
*/
- private static int getMinOfSubregion(CompoundTag nbt, String subReg, String s) {
- int a = nbt.getCompound("Regions").getCompound(subReg).getCompound("Position").getInt(s);
- int b = nbt.getCompound("Regions").getCompound(subReg).getCompound("Size").getInt(s);
- if (b < 0) {
- b++;
- }
- return Math.min(a, a + b);
-
+ private static int getMinOfSubregion(CompoundTag subReg, String s) {
+ int a = subReg.getCompound("Position").getInt(s);
+ int b = subReg.getCompound("Size").getInt(s);
+ return Math.min(a, a + b + 1);
}
/**
@@ -110,7 +97,7 @@ public final class LitematicaSchematic extends StaticSchematic {
private static BlockState getBlockState(Block block, CompoundTag properties) {
BlockState blockState = block.defaultBlockState();
- for (Object key : properties.getAllKeys().toArray()) {
+ for (Object key : properties.getAllKeys()) {
Property> property = block.getStateDefinition().getProperty((String) key);
String propertyValue = properties.getString((String) key);
if (property != null) {
@@ -146,43 +133,19 @@ public final class LitematicaSchematic extends StaticSchematic {
*
* @return the volume of the subregion.
*/
- private static long getVolume(CompoundTag nbt, String subReg) {
- return Math.abs(
- nbt.getCompound("Regions").getCompound(subReg).getCompound("Size").getInt("x") *
- nbt.getCompound("Regions").getCompound(subReg).getCompound("Size").getInt("y") *
- nbt.getCompound("Regions").getCompound(subReg).getCompound("Size").getInt("z"));
- }
-
- /**
- * @return array of Long values.
- */
- private static long[] getBlockStates(CompoundTag nbt, String subReg) {
- return nbt.getCompound("Regions").getCompound(subReg).getLongArray("BlockStates");
- }
-
- /**
- * Subregion don't have to be the same size as the enclosing size of the schematic. If they are smaller we check here if the current block is part of the subregion.
- *
- * @param x coord of the block relative to the minimum corner.
- * @param y coord of the block relative to the minimum corner.
- * @param z coord of the block relative to the minimum corner.
- * @return if the current block is part of the subregion.
- */
- private static boolean inSubregion(CompoundTag nbt, String subReg, int x, int y, int z) {
- return x >= 0 && y >= 0 && z >= 0 &&
- x < Math.abs(nbt.getCompound("Regions").getCompound(subReg).getCompound("Size").getInt("x")) &&
- y < Math.abs(nbt.getCompound("Regions").getCompound(subReg).getCompound("Size").getInt("y")) &&
- z < Math.abs(nbt.getCompound("Regions").getCompound(subReg).getCompound("Size").getInt("z"));
+ private static long getVolume(CompoundTag subReg) {
+ CompoundTag size = subReg.getCompound("Size");
+ return Math.abs(size.getInt("x") * size.getInt("y") * size.getInt("z"));
}
/**
* @param s axis.
* @return the lowest coordinate of that axis of the schematic.
*/
- private int getMinOfSchematic(String s) {
+ private static int getMinOfSchematic(CompoundTag nbt, String s) {
int n = Integer.MAX_VALUE;
- for (String subReg : getRegions(nbt)) {
- n = Math.min(n, getMinOfSubregion(nbt, subReg, s));
+ for (CompoundTag subReg : getRegions(nbt)) {
+ n = Math.min(n, getMinOfSubregion(subReg, s));
}
return n;
}
@@ -190,18 +153,18 @@ public final class LitematicaSchematic extends StaticSchematic {
/**
* reads the file data.
*/
- private void fillInSchematic() {
- for (String subReg : getRegions(nbt)) {
- ListTag usedBlockTypes = nbt.getCompound("Regions").getCompound(subReg).getList("BlockStatePalette", 10);
+ private void fillInSchematic(CompoundTag nbt) {
+ Vec3i offsetMinCorner = new Vec3i(getMinOfSchematic(nbt, "x"), getMinOfSchematic(nbt, "y"), getMinOfSchematic(nbt, "z"));
+ for (CompoundTag subReg : getRegions(nbt)) {
+ ListTag usedBlockTypes = subReg.getList("BlockStatePalette", 10);
BlockState[] blockList = getBlockList(usedBlockTypes);
int bitsPerBlock = getBitsPerBlock(usedBlockTypes.size());
- long regionVolume = getVolume(nbt, subReg);
- long[] blockStateArray = getBlockStates(nbt, subReg);
+ long regionVolume = getVolume(subReg);
+ long[] blockStateArray = subReg.getLongArray("BlockStates");
LitematicaBitArray bitArray = new LitematicaBitArray(bitsPerBlock, regionVolume, blockStateArray);
-
- writeSubregionIntoSchematic(nbt, subReg, blockList, bitArray);
+ writeSubregionIntoSchematic(subReg, offsetMinCorner, blockList, bitArray);
}
}
@@ -211,65 +174,30 @@ public final class LitematicaSchematic extends StaticSchematic {
* @param blockList list with the different block types used in the schematic.
* @param bitArray bit array that holds the placement pattern.
*/
- private void writeSubregionIntoSchematic(CompoundTag nbt, String subReg, BlockState[] blockList, LitematicaBitArray bitArray) {
- Vec3i offsetSubregion = new Vec3i(getMinOfSubregion(nbt, subReg, "x"), getMinOfSubregion(nbt, subReg, "y"), getMinOfSubregion(nbt, subReg, "z"));
+ private void writeSubregionIntoSchematic(CompoundTag subReg, Vec3i offsetMinCorner, BlockState[] blockList, LitematicaBitArray bitArray) {
+ int offsetX = getMinOfSubregion(subReg, "x") - offsetMinCorner.getX();
+ int offsetY = getMinOfSubregion(subReg, "y") - offsetMinCorner.getY();
+ int offsetZ = getMinOfSubregion(subReg, "z") - offsetMinCorner.getZ();
+ CompoundTag size = subReg.getCompound("Size");
+ int sizeX = Math.abs(size.getInt("x"));
+ int sizeY = Math.abs(size.getInt("y"));
+ int sizeZ = Math.abs(size.getInt("z"));
+ BlockState[][][] states = new BlockState[sizeX][sizeZ][sizeY];
int index = 0;
- for (int y = 0; y < this.y; y++) {
- for (int z = 0; z < this.z; z++) {
- for (int x = 0; x < this.x; x++) {
- if (inSubregion(nbt, subReg, x, y, z)) {
- this.states[x - (offsetMinCorner.getX() - offsetSubregion.getX())][z - (offsetMinCorner.getZ() - offsetSubregion.getZ())][y - (offsetMinCorner.getY() - offsetSubregion.getY())] = blockList[bitArray.getAt(index)];
- index++;
- }
+ for (int y = 0; y < sizeY; y++) {
+ for (int z = 0; z < sizeZ; z++) {
+ for (int x = 0; x < sizeX; x++) {
+ states[x][z][y] = blockList[bitArray.getAt(index)];
+ index++;
}
}
}
+ this.put(new StaticSchematic(states), offsetX, offsetY, offsetZ);
}
- /**
- * @return offset from the schematic origin to the minimum Corner as a Vec3i.
- */
- public Vec3i getOffsetMinCorner() {
- return offsetMinCorner;
- }
-
- /**
- * @return x size of the schematic.
- */
- public int getX() {
- return this.x;
- }
-
- /**
- * @return y size of the schematic.
- */
- public int getY() {
- return this.y;
- }
-
- /**
- * @return z size of the schematic.
- */
- public int getZ() {
- return this.z;
- }
-
- /**
- * @param x position relative to the minimum corner of the schematic.
- * @param y position relative to the minimum corner of the schematic.
- * @param z position relative to the minimum corner of the schematic.
- * @param blockState new blockstate of the block at this position.
- */
- public void setDirect(int x, int y, int z, BlockState blockState) {
- this.states[x][z][y] = blockState;
- }
-
- /**
- * @param rotated if the schematic is rotated by 90°.
- * @return a copy of the schematic.
- */
- public LitematicaSchematic getCopy(boolean rotated) {
- return new LitematicaSchematic(nbt, rotated);
+ @Override
+ public BlockState getDirect(int x, int y, int z) {
+ return desiredState(x, y, z, null, Collections.emptyList());
}
/**
diff --git a/src/main/java/baritone/utils/schematic/litematica/LitematicaHelper.java b/src/main/java/baritone/utils/schematic/litematica/LitematicaHelper.java
index 3b05c23ef..febe985d2 100644
--- a/src/main/java/baritone/utils/schematic/litematica/LitematicaHelper.java
+++ b/src/main/java/baritone/utils/schematic/litematica/LitematicaHelper.java
@@ -17,15 +17,26 @@
package baritone.utils.schematic.litematica;
-import baritone.utils.schematic.format.defaults.LitematicaSchematic;
+import baritone.api.schematic.CompositeSchematic;
+import baritone.api.schematic.IStaticSchematic;
+import baritone.utils.schematic.StaticSchematic;
import fi.dy.masa.litematica.Litematica;
import fi.dy.masa.litematica.data.DataManager;
+import fi.dy.masa.litematica.schematic.placement.SchematicPlacement;
+import fi.dy.masa.litematica.schematic.placement.SubRegionPlacement;
+import fi.dy.masa.litematica.world.SchematicWorldHandler;
+import fi.dy.masa.litematica.world.WorldSchematic;
+import net.minecraft.core.BlockPos;
import net.minecraft.core.Vec3i;
+import net.minecraft.util.Tuple;
+import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.state.BlockState;
-import java.io.File;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
/**
* Helper class that provides access or processes data related to Litmatica schematics.
@@ -48,168 +59,98 @@ public final class LitematicaHelper {
}
/**
- * @return if there are loaded schematics.
+ * @return if {@code i} is a valid placement index
*/
- public static boolean hasLoadedSchematic() {
- return DataManager.getSchematicPlacementManager().getAllSchematicsPlacements().size() > 0;
+ public static boolean hasLoadedSchematic(int i) {
+ return 0 <= i && i < DataManager.getSchematicPlacementManager().getAllSchematicsPlacements().size();
}
- /**
- * @param i index of the Schematic in the schematic placement list.
- * @return the name of the requested schematic.
- */
- public static String getName(int i) {
- return DataManager.getSchematicPlacementManager().getAllSchematicsPlacements().get(i).getName();
+ private static SchematicPlacement getPlacement(int i) {
+ return DataManager.getSchematicPlacementManager().getAllSchematicsPlacements().get(i);
}
- /**
- * @param i index of the Schematic in the schematic placement list.
- * @return the world coordinates of the schematic origin. This can but does not have to be the minimum corner.
- */
- public static Vec3i getOrigin(int i) {
- return DataManager.getSchematicPlacementManager().getAllSchematicsPlacements().get(i).getOrigin();
- }
-
- /**
- * @param i index of the Schematic in the schematic placement list.
- * @return Filepath of the schematic file.
- */
- public static File getSchematicFile(int i) {
- return DataManager.getSchematicPlacementManager().getAllSchematicsPlacements().get(i).getSchematicFile();
- }
-
- /**
- * @param i index of the Schematic in the schematic placement list.
- * @return rotation of the schematic placement.
- */
- public static Rotation getRotation(int i) {
- return DataManager.getSchematicPlacementManager().getAllSchematicsPlacements().get(i).getRotation();
- }
-
- /**
- * @param i index of the Schematic in the schematic placement list.
- * @return the mirroring of the schematic placement.
- */
- public static Mirror getMirror(int i) {
- return DataManager.getSchematicPlacementManager().getAllSchematicsPlacements().get(i).getMirror();
- }
-
- /**
- * @param schematic original schematic.
- * @param i index of the Schematic in the schematic placement list.
- * @return the minimum corner coordinates of the schematic, after the original schematic got rotated and mirrored.
- */
- public static Vec3i getCorrectedOrigin(LitematicaSchematic schematic, int i) {
- int x = LitematicaHelper.getOrigin(i).getX();
- int y = LitematicaHelper.getOrigin(i).getY();
- int z = LitematicaHelper.getOrigin(i).getZ();
- int mx = schematic.getOffsetMinCorner().getX();
- int my = schematic.getOffsetMinCorner().getY();
- int mz = schematic.getOffsetMinCorner().getZ();
- int sx = (schematic.getX() - 1) * -1;
- int sz = (schematic.getZ() - 1) * -1;
-
- Vec3i correctedOrigin;
- Mirror mirror = LitematicaHelper.getMirror(i);
- Rotation rotation = LitematicaHelper.getRotation(i);
-
- //todo there has to be a better way to do this but i cant finde it atm
- switch (mirror) {
- case FRONT_BACK:
- case LEFT_RIGHT:
- switch ((mirror.ordinal() * 2 + rotation.ordinal()) % 4) {
- case 1:
- correctedOrigin = new Vec3i(x + (sz - mz), y + my, z + (sx - mx));
- break;
- case 2:
- correctedOrigin = new Vec3i(x + mx, y + my, z + (sz - mz));
- break;
- case 3:
- correctedOrigin = new Vec3i(x + mz, y + my, z + mx);
- break;
- default:
- correctedOrigin = new Vec3i(x + (sx - mx), y + my, z + mz);
- break;
- }
- break;
- default:
- switch (rotation) {
- case CLOCKWISE_90:
- correctedOrigin = new Vec3i(x + (sz - mz), y + my, z + mx);
- break;
- case CLOCKWISE_180:
- correctedOrigin = new Vec3i(x + (sx - mx), y + my, z + (sz - mz));
- break;
- case COUNTERCLOCKWISE_90:
- correctedOrigin = new Vec3i(x + mz, y + my, z + (sx - mx));
- break;
- default:
- correctedOrigin = new Vec3i(x + mx, y + my, z + mz);
- break;
- }
- }
- return correctedOrigin;
- }
-
- /**
- * @param in the xyz offsets of the block relative to the schematic minimum corner.
- * @param sizeX size of the schematic in the x-axis direction.
- * @param sizeZ size of the schematic in the z-axis direction.
- * @param mirror the mirroring of the schematic placement.
- * @return the corresponding xyz coordinates after mirroring them according to the given mirroring.
- */
- public static Vec3i doMirroring(Vec3i in, int sizeX, int sizeZ, Mirror mirror) {
- int xOut = in.getX();
- int zOut = in.getZ();
+ private static Vec3i transform(Vec3i in, Mirror mirror, Rotation rotation) {
+ int x = in.getX();
+ int z = in.getZ();
if (mirror == Mirror.LEFT_RIGHT) {
- zOut = sizeZ - in.getZ();
+ z = -z;
} else if (mirror == Mirror.FRONT_BACK) {
- xOut = sizeX - in.getX();
+ x = -x;
+ }
+ switch (rotation) {
+ case CLOCKWISE_90:
+ return new Vec3i(-z, in.getY(), x);
+ case CLOCKWISE_180:
+ return new Vec3i(-x, in.getY(), -z);
+ case COUNTERCLOCKWISE_90:
+ return new Vec3i(z, in.getY(), -x);
+ default:
+ return new Vec3i(x, in.getY(), z);
}
- return new Vec3i(xOut, in.getY(), zOut);
}
/**
- * @param in the xyz offsets of the block relative to the schematic minimum corner.
- * @param sizeX size of the schematic in the x-axis direction.
- * @param sizeZ size of the schematic in the z-axis direction.
- * @return the corresponding xyz coordinates after rotation them 90° clockwise.
+ * @param i index of the Schematic in the schematic placement list.
+ * @return The transformed schematic and the position of its minimum corner
*/
- public static Vec3i rotate(Vec3i in, int sizeX, int sizeZ) {
- return new Vec3i(sizeX - (sizeX - sizeZ) - in.getZ(), in.getY(), in.getX());
- }
-
- /**
- * IDFK this just grew and it somehow works. If you understand how, pls tell me.
- *
- * @param schemIn give in the original schematic.
- * @param i index of the Schematic in the schematic placement list.
- * @return get it out rotated and mirrored.
- */
- public static LitematicaSchematic blackMagicFuckery(LitematicaSchematic schemIn, int i) {
- LitematicaSchematic tempSchem = schemIn.getCopy(LitematicaHelper.getRotation(i).ordinal() % 2 == 1);
- for (int yCounter = 0; yCounter < schemIn.getY(); yCounter++) {
- for (int zCounter = 0; zCounter < schemIn.getZ(); zCounter++) {
- for (int xCounter = 0; xCounter < schemIn.getX(); xCounter++) {
- Vec3i xyzHolder = new Vec3i(xCounter, yCounter, zCounter);
- xyzHolder = LitematicaHelper.doMirroring(xyzHolder, schemIn.getX() - 1, schemIn.getZ() - 1, LitematicaHelper.getMirror(i));
- for (int turns = 0; turns < LitematicaHelper.getRotation(i).ordinal(); turns++) {
- if ((turns % 2) == 0) {
- xyzHolder = LitematicaHelper.rotate(xyzHolder, schemIn.getX() - 1, schemIn.getZ() - 1);
- } else {
- xyzHolder = LitematicaHelper.rotate(xyzHolder, schemIn.getZ() - 1, schemIn.getX() - 1);
- }
+ public static Tuple getSchematic(int i) {
+ SchematicPlacement placement = getPlacement(i);
+ int minX = Integer.MAX_VALUE;
+ int minY = Integer.MAX_VALUE;
+ int minZ = Integer.MAX_VALUE;
+ HashMap subRegions = new HashMap<>();
+ Level schematicWorld = SchematicWorldHandler.getSchematicWorld();
+ for (Map.Entry entry : placement.getEnabledRelativeSubRegionPlacements().entrySet()) {
+ SubRegionPlacement subPlacement = entry.getValue();
+ Vec3i pos = transform(subPlacement.getPos(), placement.getMirror(), placement.getRotation());
+ Vec3i size = placement.getSchematic().getAreaSize(entry.getKey());
+ size = transform(size, placement.getMirror(), placement.getRotation());
+ size = transform(size, subPlacement.getMirror(), subPlacement.getRotation());
+ int mx = Math.min(size.getX() + 1, 0);
+ int my = Math.min(size.getY() + 1, 0);
+ int mz = Math.min(size.getZ() + 1, 0);
+ minX = Math.min(minX, pos.getX() + mx);
+ minY = Math.min(minY, pos.getY() + my);
+ minZ = Math.min(minZ, pos.getZ() + mz);
+ BlockPos origin = placement.getOrigin().offset(pos).offset(mx, my, mz);
+ BlockState[][][] states = new BlockState[Math.abs(size.getX())][Math.abs(size.getZ())][Math.abs(size.getY())];
+ for (int x = 0; x < states.length; x++) {
+ for (int z = 0; z < states[x].length; z++) {
+ for (int y = 0; y < states[x][z].length; y++) {
+ states[x][z][y] = schematicWorld.getBlockState(origin.offset(x, y, z));
}
- BlockState state = schemIn.getDirect(xCounter, yCounter, zCounter);
- try {
- state = state.mirror(LitematicaHelper.getMirror(i)).rotate(LitematicaHelper.getRotation(i));
- } catch (NullPointerException e) {
- //nothing to worry about it's just a hole in the schematic.
- }
- tempSchem.setDirect(xyzHolder.getX(), xyzHolder.getY(), xyzHolder.getZ(), state);
}
}
+ StaticSchematic schematic = new StaticSchematic(states);
+ subRegions.put(pos.offset(mx, my, mz), schematic);
}
- return tempSchem;
+ LitematicaPlacementSchematic composite = new LitematicaPlacementSchematic(placement.getName());
+ for (Map.Entry entry : subRegions.entrySet()) {
+ Vec3i pos = entry.getKey().offset(-minX, -minY, -minZ);
+ composite.put(entry.getValue(), pos.getX(), pos.getY(), pos.getZ());
+ }
+ return new Tuple<>(composite, placement.getOrigin().offset(minX, minY, minZ));
}
-}
\ No newline at end of file
+
+ private static class LitematicaPlacementSchematic extends CompositeSchematic implements IStaticSchematic {
+ private final String name;
+
+ public LitematicaPlacementSchematic(String name) {
+ super(0, 0, 0);
+ this.name = name;
+ }
+
+ @Override
+ public BlockState getDirect(int x, int y, int z) {
+ if (inSchematic(x, y, z, null)) {
+ return desiredState(x, y, z, null, Collections.emptyList());
+ }
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+ }
+}
diff --git a/src/schematica_api/java/fi/dy/masa/litematica/data/DataManager.java b/src/schematica_api/java/fi/dy/masa/litematica/data/DataManager.java
index 4941e7cf3..3f5c6c98f 100644
--- a/src/schematica_api/java/fi/dy/masa/litematica/data/DataManager.java
+++ b/src/schematica_api/java/fi/dy/masa/litematica/data/DataManager.java
@@ -20,14 +20,8 @@ package fi.dy.masa.litematica.data;
import fi.dy.masa.litematica.schematic.placement.SchematicPlacementManager;
public class DataManager {
- public static final DataManager INSTANCE = new DataManager();
- private final SchematicPlacementManager schematicPlacementManager = new SchematicPlacementManager();
-
- private static DataManager getInstance() {
- return INSTANCE;
- }
public static SchematicPlacementManager getSchematicPlacementManager() {
- return getInstance().schematicPlacementManager;
+ throw new LinkageError();
}
}
\ No newline at end of file
diff --git a/src/schematica_api/java/fi/dy/masa/litematica/schematic/LitematicaSchematic.java b/src/schematica_api/java/fi/dy/masa/litematica/schematic/LitematicaSchematic.java
new file mode 100644
index 000000000..fc8ef5c6e
--- /dev/null
+++ b/src/schematica_api/java/fi/dy/masa/litematica/schematic/LitematicaSchematic.java
@@ -0,0 +1,27 @@
+/*
+ * 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 fi.dy.masa.litematica.schematic;
+
+import net.minecraft.core.BlockPos;
+
+public class LitematicaSchematic {
+
+ public BlockPos getAreaSize(String name) {
+ throw new LinkageError();
+ }
+}
\ No newline at end of file
diff --git a/src/schematica_api/java/fi/dy/masa/litematica/schematic/placement/SchematicPlacement.java b/src/schematica_api/java/fi/dy/masa/litematica/schematic/placement/SchematicPlacement.java
index a267553a9..77f8b629e 100644
--- a/src/schematica_api/java/fi/dy/masa/litematica/schematic/placement/SchematicPlacement.java
+++ b/src/schematica_api/java/fi/dy/masa/litematica/schematic/placement/SchematicPlacement.java
@@ -17,19 +17,35 @@
package fi.dy.masa.litematica.schematic.placement;
+import com.google.common.collect.ImmutableMap;
+import fi.dy.masa.litematica.schematic.LitematicaSchematic;
+import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.Rotation;
-public class SchematicPlacement extends SchematicPlacementUnloaded {
- private Rotation rotation;
- private Mirror mirror;
+public class SchematicPlacement {
+
+ public String getName() {
+ throw new LinkageError();
+ }
+
+ public BlockPos getOrigin() {
+ throw new LinkageError();
+ }
public Rotation getRotation() {
- return this.rotation;
+ throw new LinkageError();
}
public Mirror getMirror() {
- return this.mirror;
+ throw new LinkageError();
}
+ public ImmutableMap getEnabledRelativeSubRegionPlacements() {
+ throw new LinkageError();
+ }
+
+ public LitematicaSchematic getSchematic() {
+ throw new LinkageError();
+ }
}
\ No newline at end of file
diff --git a/src/schematica_api/java/fi/dy/masa/litematica/schematic/placement/SchematicPlacementManager.java b/src/schematica_api/java/fi/dy/masa/litematica/schematic/placement/SchematicPlacementManager.java
index ab60e27fa..e7f810a5e 100644
--- a/src/schematica_api/java/fi/dy/masa/litematica/schematic/placement/SchematicPlacementManager.java
+++ b/src/schematica_api/java/fi/dy/masa/litematica/schematic/placement/SchematicPlacementManager.java
@@ -17,15 +17,13 @@
package fi.dy.masa.litematica.schematic.placement;
-import java.util.ArrayList;
import java.util.List;
public class SchematicPlacementManager {
- private final List schematicPlacements = new ArrayList<>();
//in case of a java.lang.NoSuchMethodError try change the name of this method to getAllSchematicPlacements()
//there are inconsistencies in the litematica mod about the naming of this method
public List getAllSchematicsPlacements() {
- return schematicPlacements;
+ throw new LinkageError();
}
}
\ No newline at end of file
diff --git a/src/schematica_api/java/fi/dy/masa/litematica/schematic/placement/SchematicPlacementUnloaded.java b/src/schematica_api/java/fi/dy/masa/litematica/schematic/placement/SubRegionPlacement.java
similarity index 65%
rename from src/schematica_api/java/fi/dy/masa/litematica/schematic/placement/SchematicPlacementUnloaded.java
rename to src/schematica_api/java/fi/dy/masa/litematica/schematic/placement/SubRegionPlacement.java
index 9e705dc7b..ec28ee95d 100644
--- a/src/schematica_api/java/fi/dy/masa/litematica/schematic/placement/SchematicPlacementUnloaded.java
+++ b/src/schematica_api/java/fi/dy/masa/litematica/schematic/placement/SubRegionPlacement.java
@@ -18,26 +18,20 @@
package fi.dy.masa.litematica.schematic.placement;
import net.minecraft.core.BlockPos;
+import net.minecraft.world.level.block.Mirror;
+import net.minecraft.world.level.block.Rotation;
-import javax.annotation.Nullable;
-import java.io.File;
+public class SubRegionPlacement {
-public class SchematicPlacementUnloaded {
- protected String name = "?";
- @Nullable
- protected File schematicFile;
- protected BlockPos origin = BlockPos.ZERO;
-
- public String getName() {
- return this.name;
+ public BlockPos getPos() {
+ throw new LinkageError();
}
- @Nullable
- public File getSchematicFile() {
- return this.schematicFile;
+ public Rotation getRotation() {
+ throw new LinkageError();
}
- public BlockPos getOrigin() {
- return this.origin;
+ public Mirror getMirror() {
+ throw new LinkageError();
}
}
\ No newline at end of file
diff --git a/src/schematica_api/java/fi/dy/masa/litematica/world/SchematicWorldHandler.java b/src/schematica_api/java/fi/dy/masa/litematica/world/SchematicWorldHandler.java
new file mode 100644
index 000000000..dfe6e9807
--- /dev/null
+++ b/src/schematica_api/java/fi/dy/masa/litematica/world/SchematicWorldHandler.java
@@ -0,0 +1,25 @@
+/*
+ * 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 fi.dy.masa.litematica.world;
+
+public class SchematicWorldHandler {
+
+ public static WorldSchematic getSchematicWorld() {
+ throw new LinkageError();
+ }
+}
diff --git a/src/schematica_api/java/fi/dy/masa/litematica/world/WorldSchematic.java b/src/schematica_api/java/fi/dy/masa/litematica/world/WorldSchematic.java
new file mode 100644
index 000000000..58f28b3a6
--- /dev/null
+++ b/src/schematica_api/java/fi/dy/masa/litematica/world/WorldSchematic.java
@@ -0,0 +1,27 @@
+/*
+ * 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 fi.dy.masa.litematica.world;
+
+import net.minecraft.world.level.Level;
+
+public abstract class WorldSchematic extends Level {
+ private WorldSchematic() {
+ super(null, null, null, null, null, false, false, 0, 0);
+ throw new LinkageError();
+ }
+}
diff --git a/tweaker/build.gradle b/tweaker/build.gradle
index 887d07cf2..3e4758c87 100644
--- a/tweaker/build.gradle
+++ b/tweaker/build.gradle
@@ -20,13 +20,13 @@ import baritone.gradle.task.ProguardTask
//import baritone.gradle.task.TweakerJsonAssembler
plugins {
- id "com.github.johnrengelman.shadow" version "7.0.0"
+ id "com.github.johnrengelman.shadow" version "8.0.0"
}
-minecraft {
+unimined.minecraft {
runs.client = {
mainClass = "net.minecraft.launchwrapper.Launch"
- args.addAll(["--tweakClass", "baritone.launch.BaritoneTweaker"])
+ args.addAll(["--tweakClass", "baritone.launch.tweaker.BaritoneTweaker"])
}
}
@@ -38,14 +38,15 @@ configurations {
}
dependencies {
- implementation "org.spongepowered:mixin:0.8.5"
+ implementation "org.spongepowered:mixin:${project.mixin_version}"
// for some reason mixin isn't including these...
- implementation "org.ow2.asm:asm:9.3"
- implementation "org.ow2.asm:asm-tree:9.3"
- implementation "org.ow2.asm:asm-commons:9.3"
- implementation "org.ow2.asm:asm-util:9.3"
- implementation "org.ow2.asm:asm-analysis:9.3"
+ implementation "org.ow2.asm:asm:${project.asm_version}"
+ implementation "org.ow2.asm:asm-tree:${project.asm_version}"
+ implementation "org.ow2.asm:asm-commons:${project.asm_version}"
+ implementation "org.ow2.asm:asm-util:${project.asm_version}"
+ implementation "org.ow2.asm:asm-analysis:${project.asm_version}"
+
implementation 'com.github.ImpactDevelopment:SimpleTweaker:1.2'
implementation('net.minecraft:launchwrapper:of-2.3') {
@@ -66,18 +67,18 @@ dependencies {
shadowJar {
configurations = [project.configurations.shadowCommon]
- classifier "dev-shadow"
+ archiveClassifier.set "dev-shadow"
}
remapJar {
inputFile.set shadowJar.archiveFile
dependsOn shadowJar
- classifier null
+ archiveClassifier.set null
}
jar {
- classifier "dev"
+ archiveClassifier.set "dev"
preserveFileTimestamps = false
reproducibleFileOrder = true
@@ -94,8 +95,7 @@ jar {
}
task proguard(type: ProguardTask) {
- url 'https://github.com/Guardsquare/proguard/releases/download/v7.2.1/proguard-7.2.1.zip'
- extract 'proguard-7.2.1/lib/proguard.jar'
+ proguardVersion "7.2.1"
}
task createDist(type: CreateDistTask, dependsOn: proguard)
diff --git a/tweaker/src/main/java/baritone/launch/BaritoneTweaker.java b/tweaker/src/main/java/baritone/launch/tweaker/BaritoneTweaker.java
similarity index 98%
rename from tweaker/src/main/java/baritone/launch/BaritoneTweaker.java
rename to tweaker/src/main/java/baritone/launch/tweaker/BaritoneTweaker.java
index b9db9b6a5..694aef533 100644
--- a/tweaker/src/main/java/baritone/launch/BaritoneTweaker.java
+++ b/tweaker/src/main/java/baritone/launch/tweaker/BaritoneTweaker.java
@@ -15,7 +15,7 @@
* along with Baritone. If not, see .
*/
-package baritone.launch;
+package baritone.launch.tweaker;
import io.github.impactdevelopment.simpletweaker.SimpleTweaker;
import net.minecraft.launchwrapper.Launch;