diff --git a/.github/workflows/gradle_build.yml b/.github/workflows/gradle_build.yml index 1fe68774e..2e808f8c4 100644 --- a/.github/workflows/gradle_build.yml +++ b/.github/workflows/gradle_build.yml @@ -13,12 +13,12 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up JDK 17 - uses: actions/setup-java@v2 + uses: actions/setup-java@v3 with: java-version: '17' - distribution: 'adopt' + distribution: 'temurin' - name: Grant execute permission for gradlew run: chmod +x gradlew @@ -33,13 +33,13 @@ jobs: run: ./gradlew build -Pbaritone.forge_build -Ploom.platform=forge - name: Archive Artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: Artifacts path: dist/ - name: Archive mapping.txt - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: Mappings path: build/tmp/proguard/mapping.txt diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index f8393273d..702ee16cf 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -11,12 +11,12 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up JDK 17 - uses: actions/setup-java@v2 + uses: actions/setup-java@v3 with: java-version: '17' - distribution: 'adopt' + distribution: 'temurin' - name: Grant execute permission for gradlew run: chmod +x gradlew diff --git a/README.md b/README.md index c50caf56a..e2c83ddec 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,9 @@ Baritone is the pathfinding system used in [Impact](https://impactclient.net/) s [Tutorial playlist](https://www.youtube.com/playlist?list=PLnwnJ1qsS7CoQl9Si-RTluuzCo_4Oulpa) -The easiest way to install Baritone is to install [Impact](https://impactclient.net/), which comes with Baritone. The second easiest way (for 1.12.2 only) is to install the v1.2.* `api-forge` jar from [releases](https://github.com/cabaletta/baritone/releases). **For 1.12.2 Forge, just click [here](https://github.com/cabaletta/baritone/releases/download/v1.2.15/baritone-api-forge-1.2.15.jar)**. Otherwise, see [Installation & setup](SETUP.md). Once Baritone is installed, look [here](USAGE.md) for instructions on how to use it. +The easiest way to install Baritone is to install [Impact](https://impactclient.net/), which comes with Baritone. The second easiest way (for 1.12.2 only) is to +install the v1.2.* `api-forge` jar from [releases](https://github.com/cabaletta/baritone/releases). **For 1.12.2 Forge, just click +[here](https://github.com/cabaletta/baritone/releases/download/v1.2.17/baritone-api-forge-1.2.17.jar)**. Otherwise, see [Installation & setup](SETUP.md). Once Baritone is installed, look [here](USAGE.md) for instructions on how to use it. For 1.16.5, [click here](https://www.youtube.com/watch?v=_4eVJ9Qz2J8) and see description. If you need Forge or Fabric 1.16.5, look [here](https://github.com/cabaletta/baritone/releases/tag/v1.6.3) and get the `api-forge` or `api-fabric` jar. **For 1.16.5 Fabric, just click [here](https://github.com/cabaletta/baritone/releases/download/v1.6.3/baritone-api-fabric-1.6.3.jar)**. diff --git a/buildSrc/src/main/java/baritone/gradle/task/ProguardTask.java b/buildSrc/src/main/java/baritone/gradle/task/ProguardTask.java index aa5e36be0..ce5211dc6 100644 --- a/buildSrc/src/main/java/baritone/gradle/task/ProguardTask.java +++ b/buildSrc/src/main/java/baritone/gradle/task/ProguardTask.java @@ -237,8 +237,8 @@ public class ProguardTask extends BaritoneGradleTask { // Setup the template that will be used to derive the API and Standalone configs List template = Files.readAllLines(getTemporaryFile(PROGUARD_CONFIG_DEST)); - template.add(0, "-injars " + this.artifactPath.toString()); - template.add(1, "-outjars " + this.getTemporaryFile(PROGUARD_EXPORT_PATH)); + template.add(0, "-injars '" + this.artifactPath.toString() + "'"); + template.add(1, "-outjars '" + this.getTemporaryFile(PROGUARD_EXPORT_PATH) + "'"); template.add(2, "-libraryjars /jmods/java.base.jmod(!**.jar;!module-info.class)"); template.add(3, "-libraryjars /jmods/java.desktop.jmod(!**.jar;!module-info.class)"); @@ -312,9 +312,15 @@ public class ProguardTask extends BaritoneGradleTask { Files.delete(this.proguardOut); } - Path proguardJar = getTemporaryFile(PROGUARD_JAR); + // Make paths relative to work directory; fixes spaces in path to config, @"" doesn't work + Path workingDirectory = getTemporaryFile(""); + Path proguardJar = workingDirectory.relativize(getTemporaryFile(PROGUARD_JAR)); + config = workingDirectory.relativize(config); + + // Honestly, if you still have spaces in your path at this point, you're SOL. + Process p = new ProcessBuilder("java", "-jar", proguardJar.toString(), "@" + config.toString()) - .directory(getTemporaryFile("").toFile()) // Set the working directory to the temporary folder] + .directory(workingDirectory.toFile()) // Set the working directory to the temporary folder] .start(); // We can't do output inherit process I/O with gradle for some reason and have it work, so we have to do this diff --git a/src/api/java/baritone/api/Settings.java b/src/api/java/baritone/api/Settings.java index 672abe160..61bc2f32a 100644 --- a/src/api/java/baritone/api/Settings.java +++ b/src/api/java/baritone/api/Settings.java @@ -35,8 +35,8 @@ import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.*; import java.util.List; -import java.util.function.Consumer; import java.util.function.BiConsumer; +import java.util.function.Consumer; /** * Baritone's settings. Settings apply to all Baritone instances. @@ -108,6 +108,13 @@ public final class Settings { */ public final Setting walkOnWaterOnePenalty = new Setting<>(3D); + /** + * Don't allow breaking blocks next to liquids. + *

+ * Enable if you have mods adding custom fluid physics. + */ + public final Setting strictLiquidCheck = new Setting<>(false); + /** * Allow Baritone to fall arbitrary distances and place a water bucket beneath it. * Reliability: questionable. @@ -117,6 +124,8 @@ public final class Settings { /** * Allow Baritone to assume it can walk on still water just like any other block. * This functionality is assumed to be provided by a separate library that might have imported Baritone. + *

+ * Note: This will prevent some usage of the frostwalker enchantment, like pillaring up from water. */ public final Setting assumeWalkOnWater = new Setting<>(false); @@ -197,7 +206,7 @@ public final class Settings { * Blocks that Baritone is not allowed to break */ public final Setting> blocksToDisallowBreaking = new Setting<>(new ArrayList<>( - // Leave Empty by Default + // Leave Empty by Default )); /** @@ -277,6 +286,12 @@ public final class Settings { */ public final Setting buildIgnoreDirection = new Setting<>(false); + /** + * A list of names of block properties the builder will ignore. + */ + public final Setting> buildIgnoreProperties = new Setting<>(new ArrayList<>(Arrays.asList( + ))); + /** * If this setting is true, Baritone will never break a block that is adjacent to an unsupported falling block. *

@@ -916,7 +931,7 @@ public final class Settings { /** * Only build the selected part of schematics */ - public final Setting buildOnlySelection = new Setting<>(false); + public final Setting buildOnlySelection = new Setting<>(false); /** * How far to move before repeating the build. 0 to disable repeating on a certain axis, 0,0,0 to disable entirely diff --git a/src/api/java/baritone/api/command/datatypes/RelativeCoordinate.java b/src/api/java/baritone/api/command/datatypes/RelativeCoordinate.java index 7d77a96c7..3d0f2613f 100644 --- a/src/api/java/baritone/api/command/datatypes/RelativeCoordinate.java +++ b/src/api/java/baritone/api/command/datatypes/RelativeCoordinate.java @@ -26,7 +26,8 @@ import java.util.stream.Stream; public enum RelativeCoordinate implements IDatatypePost { INSTANCE; - private static Pattern PATTERN = Pattern.compile("^(~?)([+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)([k-k]?)|)$"); + private static String ScalesAliasRegex = "[kKmM]"; + private static Pattern PATTERN = Pattern.compile("^(~?)([+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)(" + ScalesAliasRegex + "?)|)$"); @Override public Double apply(IDatatypeContext ctx, Double origin) throws CommandException { @@ -41,11 +42,15 @@ public enum RelativeCoordinate implements IDatatypePost { boolean isRelative = !matcher.group(1).isEmpty(); - double offset = matcher.group(2).isEmpty() ? 0 : Double.parseDouble(matcher.group(2).replaceAll("k", "")); + double offset = matcher.group(2).isEmpty() ? 0 : Double.parseDouble(matcher.group(2).replaceAll(ScalesAliasRegex, "")); - if (matcher.group(2).contains("k")) { + if (matcher.group(2).toLowerCase().contains("k")) { offset *= 1000; } + if (matcher.group(2).toLowerCase().contains("m")) { + offset *= 1000000; + } + if (isRelative) { return origin + offset; diff --git a/src/api/java/baritone/api/command/datatypes/RelativeFile.java b/src/api/java/baritone/api/command/datatypes/RelativeFile.java index f2de7308c..7d7e6899b 100644 --- a/src/api/java/baritone/api/command/datatypes/RelativeFile.java +++ b/src/api/java/baritone/api/command/datatypes/RelativeFile.java @@ -83,10 +83,10 @@ public enum RelativeFile implements IDatatypePost { boolean useParent = !currentPathStringThing.isEmpty() && !currentPathStringThing.endsWith(File.separator); File currentFile = currentPath.isAbsolute() ? currentPath.toFile() : new File(base, currentPathStringThing); return Stream.of(Objects.requireNonNull(getCanonicalFileUnchecked( - useParent - ? currentFile.getParentFile() - : currentFile - ).listFiles())) + useParent + ? currentFile.getParentFile() + : currentFile + ).listFiles())) .map(f -> (currentPath.isAbsolute() ? f : basePath.relativize(f.toPath()).toString()) + (f.isDirectory() ? File.separator : "")) .filter(s -> s.toLowerCase(Locale.US).startsWith(currentPathStringThing.toLowerCase(Locale.US))) diff --git a/src/api/java/baritone/api/command/registry/Registry.java b/src/api/java/baritone/api/command/registry/Registry.java index 067791690..b571484b7 100644 --- a/src/api/java/baritone/api/command/registry/Registry.java +++ b/src/api/java/baritone/api/command/registry/Registry.java @@ -84,7 +84,7 @@ public class Registry { * @param entry The entry to unregister. */ public void unregister(V entry) { - if (registered(entry)) { + if (!registered(entry)) { return; } _entries.remove(entry); diff --git a/src/api/java/baritone/api/pathing/goals/GoalNear.java b/src/api/java/baritone/api/pathing/goals/GoalNear.java index 71bdc8ebd..6ee35ad7b 100644 --- a/src/api/java/baritone/api/pathing/goals/GoalNear.java +++ b/src/api/java/baritone/api/pathing/goals/GoalNear.java @@ -19,8 +19,8 @@ package baritone.api.pathing.goals; import baritone.api.utils.SettingsUtil; import baritone.api.utils.interfaces.IGoalRenderPos; -import it.unimi.dsi.fastutil.doubles.DoubleOpenHashSet; import it.unimi.dsi.fastutil.doubles.DoubleIterator; +import it.unimi.dsi.fastutil.doubles.DoubleOpenHashSet; import net.minecraft.core.BlockPos; public class GoalNear implements Goal, IGoalRenderPos { diff --git a/src/api/java/baritone/api/pathing/goals/GoalRunAway.java b/src/api/java/baritone/api/pathing/goals/GoalRunAway.java index 9fe3421d6..3906713f2 100644 --- a/src/api/java/baritone/api/pathing/goals/GoalRunAway.java +++ b/src/api/java/baritone/api/pathing/goals/GoalRunAway.java @@ -18,11 +18,12 @@ package baritone.api.pathing.goals; import baritone.api.utils.SettingsUtil; -import it.unimi.dsi.fastutil.doubles.DoubleOpenHashSet; import it.unimi.dsi.fastutil.doubles.DoubleIterator; -import java.util.Arrays; +import it.unimi.dsi.fastutil.doubles.DoubleOpenHashSet; import net.minecraft.core.BlockPos; +import java.util.Arrays; + /** * Useful for automated combat (retreating specifically) * diff --git a/src/api/java/baritone/api/schematic/SubstituteSchematic.java b/src/api/java/baritone/api/schematic/SubstituteSchematic.java index 0d8583c32..96baa38da 100644 --- a/src/api/java/baritone/api/schematic/SubstituteSchematic.java +++ b/src/api/java/baritone/api/schematic/SubstituteSchematic.java @@ -34,7 +34,7 @@ public class SubstituteSchematic extends AbstractSchematic { private final Map> substitutions; private final Map> blockStateCache = new HashMap<>(); - public SubstituteSchematic(ISchematic schematic, Map> substitutions) { + public SubstituteSchematic(ISchematic schematic, Map> substitutions) { super(schematic.widthX(), schematic.heightY(), schematic.lengthZ()); this.schematic = schematic; this.substitutions = substitutions; @@ -81,9 +81,10 @@ public class SubstituteSchematic extends AbstractSchematic { } catch (IllegalArgumentException e) { //property does not exist for target block } } - blockStateCache.computeIfAbsent(state, s -> new HashMap()).put(block, newState); + blockStateCache.computeIfAbsent(state, s -> new HashMap()).put(block, newState); return newState; } + private > BlockState copySingleProp(BlockState fromState, BlockState toState, Property prop) { return toState.setValue(prop, fromState.getValue(prop)); } diff --git a/src/api/java/baritone/api/utils/SettingsUtil.java b/src/api/java/baritone/api/utils/SettingsUtil.java index 2ed98d92f..5b9358a21 100644 --- a/src/api/java/baritone/api/utils/SettingsUtil.java +++ b/src/api/java/baritone/api/utils/SettingsUtil.java @@ -178,7 +178,7 @@ public class SettingsUtil { /** * This should always be the same as whether the setting can be parsed from or serialized to a string * - * @param the setting + * @param setting The Setting * @return true if the setting can not be set or read by the user */ public static boolean javaOnlySetting(Settings.Setting setting) { @@ -300,7 +300,7 @@ public class SettingsUtil { Parser keyParser = Parser.getParser(keyType); Parser valueParser = Parser.getParser(valueType); - return ((Map) value).entrySet().stream() + return ((Map) value).entrySet().stream() .map(o -> keyParser.toString(context, o.getKey()) + "->" + valueParser.toString(context, o.getValue())) .collect(Collectors.joining(",")); } diff --git a/src/launch/java/baritone/launch/mixins/MixinLongArrayNBT.java b/src/launch/java/baritone/launch/mixins/MixinLongArrayNBT.java deleted file mode 100644 index 0a9c938d9..000000000 --- a/src/launch/java/baritone/launch/mixins/MixinLongArrayNBT.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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.launch.mixins; - -import baritone.utils.accessor.ILongArrayNBT; -import net.minecraft.nbt.LongArrayTag; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -/** - * @author rycbar - * @since 26.09.2022 - */ -@Mixin(LongArrayTag.class) -public abstract class MixinLongArrayNBT implements ILongArrayNBT { - - @Accessor("data") - @Override - public abstract long[] getLongArray(); -} \ No newline at end of file diff --git a/src/launch/resources/mixins.baritone.json b/src/launch/resources/mixins.baritone.json index 72fb8eda3..d3907b80f 100644 --- a/src/launch/resources/mixins.baritone.json +++ b/src/launch/resources/mixins.baritone.json @@ -19,7 +19,6 @@ "MixinLivingEntity", "MixinLootContext", "MixinMinecraft", - "MixinLongArrayNBT", "MixinNetworkManager", "MixinPlayerController", "MixinScreen", diff --git a/src/main/java/baritone/behavior/InventoryBehavior.java b/src/main/java/baritone/behavior/InventoryBehavior.java index 04907203b..570a3e1c8 100644 --- a/src/main/java/baritone/behavior/InventoryBehavior.java +++ b/src/main/java/baritone/behavior/InventoryBehavior.java @@ -18,7 +18,6 @@ package baritone.behavior; import baritone.Baritone; -import baritone.api.BaritoneAPI; import baritone.api.event.events.TickEvent; import baritone.utils.ToolSet; import net.minecraft.client.player.LocalPlayer; diff --git a/src/main/java/baritone/behavior/PathingBehavior.java b/src/main/java/baritone/behavior/PathingBehavior.java index 0082fdcf8..e65d5f069 100644 --- a/src/main/java/baritone/behavior/PathingBehavior.java +++ b/src/main/java/baritone/behavior/PathingBehavior.java @@ -98,6 +98,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, baritone.getPathingControlManager().cancelEverything(); return; } + expectedSegmentStart = pathStart(); baritone.getPathingControlManager().preTick(); tickPath(); diff --git a/src/main/java/baritone/behavior/WaypointBehavior.java b/src/main/java/baritone/behavior/WaypointBehavior.java index 3e6bac30e..907bf727d 100644 --- a/src/main/java/baritone/behavior/WaypointBehavior.java +++ b/src/main/java/baritone/behavior/WaypointBehavior.java @@ -72,21 +72,21 @@ public class WaypointBehavior extends Behavior { baritone.getWorldProvider().getCurrentWorld().getWaypoints().addWaypoint(deathWaypoint); BaseComponent component = new TextComponent("Death position saved."); component.setStyle(component.getStyle() - .withColor(ChatFormatting.WHITE) - .withHoverEvent(new HoverEvent( - HoverEvent.Action.SHOW_TEXT, - new TextComponent("Click to goto death") - )) - .withClickEvent(new ClickEvent( - ClickEvent.Action.RUN_COMMAND, - String.format( - "%s%s goto %s @ %d", - FORCE_COMMAND_PREFIX, - "wp", - deathWaypoint.getTag().getName(), - deathWaypoint.getCreationTimestamp() - ) - ))); + .withColor(ChatFormatting.WHITE) + .withHoverEvent(new HoverEvent( + HoverEvent.Action.SHOW_TEXT, + new TextComponent("Click to goto death") + )) + .withClickEvent(new ClickEvent( + ClickEvent.Action.RUN_COMMAND, + String.format( + "%s%s goto %s @ %d", + FORCE_COMMAND_PREFIX, + "wp", + deathWaypoint.getTag().getName(), + deathWaypoint.getCreationTimestamp() + ) + ))); Helper.HELPER.logDirect(component); } diff --git a/src/main/java/baritone/cache/WorldData.java b/src/main/java/baritone/cache/WorldData.java index 7c9de6baa..b8efb5e1c 100644 --- a/src/main/java/baritone/cache/WorldData.java +++ b/src/main/java/baritone/cache/WorldData.java @@ -21,12 +21,10 @@ import baritone.Baritone; import baritone.api.cache.ICachedWorld; import baritone.api.cache.IWaypointCollection; import baritone.api.cache.IWorldData; -import java.io.IOException; -import java.nio.file.Path; -import net.minecraft.resources.ResourceKey; -import net.minecraft.world.level.Level; import net.minecraft.world.level.dimension.DimensionType; +import java.nio.file.Path; + /** * Data about a world, from baritone's point of view. Includes cached chunks, waypoints, and map data. * diff --git a/src/main/java/baritone/cache/WorldProvider.java b/src/main/java/baritone/cache/WorldProvider.java index f4f448106..f3d96a0db 100644 --- a/src/main/java/baritone/cache/WorldProvider.java +++ b/src/main/java/baritone/cache/WorldProvider.java @@ -45,9 +45,11 @@ public class WorldProvider implements IWorldProvider, Helper { private static final Map worldCache = new HashMap<>(); // this is how the bots have the same cached world private WorldData currentWorld; + private Level mcWorld; // this let's us detect a broken load/unload hook @Override public final WorldData getCurrentWorld() { + detectAndHandleBrokenLoading(); return this.currentWorld; } @@ -76,16 +78,14 @@ public class WorldProvider implements IWorldProvider, Helper { readme = directory; } else { // Otherwise, the server must be remote... String folderName; - if (mc.isConnectedToRealms()) { - folderName = "realms"; + if (mc.getCurrentServer() != null) { + folderName = mc.isConnectedToRealms() ? "realms" : mc.getCurrentServer().ip; } else { - if (mc.getCurrentServer() != null) { - folderName = mc.getCurrentServer().ip; - } else { - //replaymod causes null currentServerData and false singleplayer. - currentWorld = null; - return; - } + //replaymod causes null currentServer and false singleplayer. + System.out.println("World seems to be a replay. Not loading Baritone cache."); + currentWorld = null; + mcWorld = mc.level; + return; } if (SystemUtils.IS_OS_WINDOWS) { folderName = folderName.replace(":", "_"); @@ -112,6 +112,7 @@ public class WorldProvider implements IWorldProvider, Helper { synchronized (worldCache) { this.currentWorld = worldCache.computeIfAbsent(dir, d -> new WorldData(d, world)); } + this.mcWorld = mc.level; } public final Path getDimDir(ResourceKey level, int height, Path directory) { @@ -121,6 +122,7 @@ public class WorldProvider implements IWorldProvider, Helper { public final void closeWorld() { WorldData world = this.currentWorld; this.currentWorld = null; + this.mcWorld = null; if (world == null) { return; } @@ -128,8 +130,25 @@ public class WorldProvider implements IWorldProvider, Helper { } public final void ifWorldLoaded(Consumer currentWorldConsumer) { + detectAndHandleBrokenLoading(); if (this.currentWorld != null) { currentWorldConsumer.accept(this.currentWorld); } } + + private final void detectAndHandleBrokenLoading() { + if (this.mcWorld != mc.level) { + if (this.currentWorld != null) { + System.out.println("mc.world unloaded unnoticed! Unloading Baritone cache now."); + closeWorld(); + } + if (mc.level != null) { + System.out.println("mc.world loaded unnoticed! Loading Baritone cache now."); + initWorld(mc.level.dimension(), mc.level.dimensionType()); + } + } else if (currentWorld == null && mc.level != null && (mc.hasSingleplayerServer() || mc.getCurrentServer() != null)) { + System.out.println("Retrying to load Baritone cache"); + initWorld(mc.level.dimension(), mc.level.dimensionType()); + } + } } diff --git a/src/main/java/baritone/command/defaults/ETACommand.java b/src/main/java/baritone/command/defaults/ETACommand.java index 47b6ae9fa..4116d65b0 100644 --- a/src/main/java/baritone/command/defaults/ETACommand.java +++ b/src/main/java/baritone/command/defaults/ETACommand.java @@ -18,17 +18,16 @@ package baritone.command.defaults; import baritone.api.IBaritone; -import baritone.api.pathing.calc.IPathingControlManager; -import baritone.api.process.IBaritoneProcess; import baritone.api.behavior.IPathingBehavior; import baritone.api.command.Command; +import baritone.api.command.argument.IArgConsumer; import baritone.api.command.exception.CommandException; import baritone.api.command.exception.CommandInvalidStateException; -import baritone.api.command.argument.IArgConsumer; +import baritone.api.pathing.calc.IPathingControlManager; +import baritone.api.process.IBaritoneProcess; import java.util.Arrays; import java.util.List; -import java.util.Optional; import java.util.stream.Stream; public class ETACommand extends Command { diff --git a/src/main/java/baritone/command/defaults/ExecutionControlCommands.java b/src/main/java/baritone/command/defaults/ExecutionControlCommands.java index eaab75286..6f6293ccd 100644 --- a/src/main/java/baritone/command/defaults/ExecutionControlCommands.java +++ b/src/main/java/baritone/command/defaults/ExecutionControlCommands.java @@ -56,6 +56,7 @@ public class ExecutionControlCommands { @Override public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) { + baritone.getInputOverrideHandler().clearAllKeys(); return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE); } diff --git a/src/main/java/baritone/command/defaults/FindCommand.java b/src/main/java/baritone/command/defaults/FindCommand.java index 07af1490d..311257802 100644 --- a/src/main/java/baritone/command/defaults/FindCommand.java +++ b/src/main/java/baritone/command/defaults/FindCommand.java @@ -79,11 +79,10 @@ public class FindCommand extends Command { BaseComponent baseComponent = new TextComponent(pos.toString()); BaseComponent hoverComponent = new TextComponent("Click to set goal to this position"); baseComponent.setStyle(baseComponent.getStyle() - .withColor(ChatFormatting.GRAY) - .withInsertion(positionText) - .withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, command)) - .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, hoverComponent)) - ); + .withColor(ChatFormatting.GRAY) + .withInsertion(positionText) + .withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, command)) + .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, hoverComponent))); return baseComponent; } @@ -91,9 +90,9 @@ public class FindCommand extends Command { public Stream tabComplete(String label, IArgConsumer args) throws CommandException { return new TabCompleteHelper() .append( - CachedChunk.BLOCKS_TO_KEEP_TRACK_OF.stream() - .map(Registry.BLOCK::getKey) - .map(Object::toString) + CachedChunk.BLOCKS_TO_KEEP_TRACK_OF.stream() + .map(Registry.BLOCK::getKey) + .map(Object::toString) ) .filterPrefixNamespaced(args.getString()) .sortAlphabetically() diff --git a/src/main/java/baritone/command/defaults/SelCommand.java b/src/main/java/baritone/command/defaults/SelCommand.java index b4ba0ce59..c5b82932d 100644 --- a/src/main/java/baritone/command/defaults/SelCommand.java +++ b/src/main/java/baritone/command/defaults/SelCommand.java @@ -36,8 +36,8 @@ import baritone.api.selection.ISelectionManager; import baritone.api.utils.BetterBlockPos; import baritone.api.utils.BlockOptionalMeta; import baritone.api.utils.BlockOptionalMetaLookup; -import baritone.utils.IRenderer; import baritone.utils.BlockStateInterface; +import baritone.utils.IRenderer; import baritone.utils.schematic.StaticSchematic; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -193,7 +193,7 @@ public class SelCommand extends Command { } } } - ISchematic schematic = new StaticSchematic(){{ + ISchematic schematic = new StaticSchematic() {{ states = blockstates; x = size.getX(); y = size.getY(); diff --git a/src/main/java/baritone/command/defaults/SetCommand.java b/src/main/java/baritone/command/defaults/SetCommand.java index 41832f3e2..9d8086b74 100644 --- a/src/main/java/baritone/command/defaults/SetCommand.java +++ b/src/main/java/baritone/command/defaults/SetCommand.java @@ -146,7 +146,8 @@ public class SetCommand extends Command { throw new CommandInvalidTypeException(args.consumed(), "a toggleable setting", "some other setting"); } //noinspection unchecked - ((Settings.Setting) setting).value ^= true; + Settings.Setting asBoolSetting = (Settings.Setting) setting; + asBoolSetting.value ^= true; logDirect(String.format( "Toggled setting %s to %s", setting.getName(), diff --git a/src/main/java/baritone/command/defaults/WaypointsCommand.java b/src/main/java/baritone/command/defaults/WaypointsCommand.java index 6c13ae35f..0c1ad5e1c 100644 --- a/src/main/java/baritone/command/defaults/WaypointsCommand.java +++ b/src/main/java/baritone/command/defaults/WaypointsCommand.java @@ -20,8 +20,8 @@ package baritone.command.defaults; import baritone.Baritone; import baritone.api.IBaritone; import baritone.api.cache.IWaypoint; -import baritone.api.cache.Waypoint; import baritone.api.cache.IWorldData; +import baritone.api.cache.Waypoint; import baritone.api.command.Command; import baritone.api.command.argument.IArgConsumer; import baritone.api.command.datatypes.ForWaypoints; @@ -50,7 +50,7 @@ import static baritone.api.command.IBaritoneChatControl.FORCE_COMMAND_PREFIX; public class WaypointsCommand extends Command { - private Map> deletedWaypoints = new HashMap<>(); + private Map> deletedWaypoints = new HashMap<>(); public WaypointsCommand(IBaritone baritone) { super(baritone, "waypoints", "waypoint", "wp"); diff --git a/src/main/java/baritone/pathing/movement/CalculationContext.java b/src/main/java/baritone/pathing/movement/CalculationContext.java index a625c63e2..c1cc0daf5 100644 --- a/src/main/java/baritone/pathing/movement/CalculationContext.java +++ b/src/main/java/baritone/pathing/movement/CalculationContext.java @@ -21,15 +21,17 @@ import baritone.Baritone; import baritone.api.IBaritone; import baritone.api.pathing.movement.ActionCosts; import baritone.cache.WorldData; +import baritone.pathing.precompute.PrecomputedData; import baritone.utils.BlockStateInterface; import baritone.utils.ToolSet; import baritone.utils.pathing.BetterWorldBorder; import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.BlockPos; import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.enchantment.EnchantmentHelper; +import net.minecraft.world.item.enchantment.Enchantments; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; @@ -64,6 +66,7 @@ public class CalculationContext { public final boolean allowJumpAt256; public final boolean allowParkourAscend; public final boolean assumeWalkOnWater; + public final int frostWalker; public final boolean allowDiagonalDescend; public final boolean allowDiagonalAscend; public final boolean allowDownward; @@ -76,11 +79,14 @@ public class CalculationContext { public final double walkOnWaterOnePenalty; public final BetterWorldBorder worldBorder; + public final PrecomputedData precomputedData; + public CalculationContext(IBaritone baritone) { this(baritone, false); } public CalculationContext(IBaritone baritone, boolean forUseOnAnotherThread) { + this.precomputedData = new PrecomputedData(); this.safeForThreadedUse = forUseOnAnotherThread; this.baritone = baritone; LocalPlayer player = baritone.getPlayerContext().player(); @@ -99,6 +105,7 @@ public class CalculationContext { this.allowJumpAt256 = Baritone.settings().allowJumpAt256.value; this.allowParkourAscend = Baritone.settings().allowParkourAscend.value; this.assumeWalkOnWater = Baritone.settings().assumeWalkOnWater.value; + this.frostWalker = EnchantmentHelper.getEnchantmentLevel(Enchantments.FROST_WALKER, baritone.getPlayerContext().player()); this.allowDiagonalDescend = Baritone.settings().allowDiagonalDescend.value; this.allowDiagonalAscend = Baritone.settings().allowDiagonalAscend.value; this.allowDownward = Baritone.settings().allowDownward.value; diff --git a/src/main/java/baritone/pathing/movement/MovementHelper.java b/src/main/java/baritone/pathing/movement/MovementHelper.java index 658e044aa..46f6e8e8a 100644 --- a/src/main/java/baritone/pathing/movement/MovementHelper.java +++ b/src/main/java/baritone/pathing/movement/MovementHelper.java @@ -26,29 +26,35 @@ import baritone.api.utils.*; import baritone.api.utils.Rotation; import baritone.api.utils.input.Input; import baritone.pathing.movement.MovementState.MovementTarget; +import baritone.pathing.precompute.Ternary; import baritone.utils.BlockStateInterface; import baritone.utils.ToolSet; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; -import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.item.enchantment.EnchantmentHelper; import net.minecraft.world.level.block.*; import net.minecraft.world.level.block.piston.MovingPistonBlock; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.level.block.state.properties.Half; import net.minecraft.world.level.block.state.properties.SlabType; +import net.minecraft.world.level.block.state.properties.StairsShape; import net.minecraft.world.level.material.FlowingFluid; import net.minecraft.world.level.material.Fluid; -import net.minecraft.world.level.material.FluidState; import net.minecraft.world.level.material.Fluids; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.level.material.Material; import net.minecraft.world.level.material.WaterFluid; import net.minecraft.world.level.pathfinder.PathComputationType; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.Vec3; + import java.util.List; import java.util.Optional; import static baritone.pathing.movement.Movement.HORIZONTALS_BUT_ALSO_DOWN_____SO_EVERY_DIRECTION_EXCEPT_UP; +import static baritone.pathing.precompute.Ternary.*; /** * Static helpers for cost calculation @@ -58,7 +64,7 @@ import static baritone.pathing.movement.Movement.HORIZONTALS_BUT_ALSO_DOWN_____S public interface MovementHelper extends ActionCosts, Helper { static boolean avoidBreaking(BlockStateInterface bsi, int x, int y, int z, BlockState state) { - if (!bsi.worldBorder.canPlaceAt(x, y)) { + if (!bsi.worldBorder.canPlaceAt(x, z)) { return true; } Block b = state.getBlock(); @@ -86,6 +92,19 @@ public interface MovementHelper extends ActionCosts, Helper { && FallingBlock.isFree(bsi.get0(x, y - 1, z))) { // and if it would fall (i.e. it's unsupported) return true; // dont break a block that is adjacent to unsupported gravel because it can cause really weird stuff } + // only pure liquids for now + // waterlogged blocks can have closed bottom sides and such + if (block instanceof LiquidBlock) { + if (directlyAbove || Baritone.settings().strictLiquidCheck.value) { + return true; + } + int level = state.getValue(LiquidBlock.LEVEL); + if (level == 0) { + return true; // source blocks like to flow horizontally + } + // everything else will prefer flowing down + return !(bsi.get0(x, y - 1, z).getBlock() instanceof LiquidBlock); // assume everything is in a static state + } return !state.getFluidState().isEmpty(); } @@ -97,35 +116,88 @@ public interface MovementHelper extends ActionCosts, Helper { return canWalkThrough(bsi, x, y, z, bsi.get0(x, y, z)); } + static boolean canWalkThrough(CalculationContext context, int x, int y, int z, BlockState state) { + return context.precomputedData.canWalkThrough(context.bsi, x, y, z, state); + } + + static boolean canWalkThrough(CalculationContext context, int x, int y, int z) { + return context.precomputedData.canWalkThrough(context.bsi, x, y, z, context.get(x, y, z)); + } + static boolean canWalkThrough(BlockStateInterface bsi, int x, int y, int z, BlockState state) { - Block block = state.getBlock(); - if (block instanceof AirBlock) { // early return for most common case + Ternary canWalkThrough = canWalkThroughBlockState(state); + if (canWalkThrough == YES) { return true; } - if (block instanceof BaseFireBlock || block == Blocks.TRIPWIRE || block == Blocks.COBWEB || block == Blocks.END_PORTAL || block == Blocks.COCOA || block instanceof AbstractSkullBlock || block == Blocks.BUBBLE_COLUMN || block instanceof ShulkerBoxBlock || block instanceof SlabBlock || block instanceof TrapDoorBlock || block == Blocks.HONEY_BLOCK || block == Blocks.END_ROD || block == Blocks.SWEET_BERRY_BUSH || block == Blocks.POINTED_DRIPSTONE || block instanceof AmethystClusterBlock || block instanceof AzaleaBlock) { + if (canWalkThrough == NO) { return false; } + return canWalkThroughPosition(bsi, x, y, z, state); + } + + static Ternary canWalkThroughBlockState(BlockState state) { + Block block = state.getBlock(); + if (block instanceof AirBlock) { + return YES; + } + if (block instanceof BaseFireBlock || block == Blocks.TRIPWIRE || block == Blocks.COBWEB || block == Blocks.END_PORTAL || block == Blocks.COCOA || block instanceof AbstractSkullBlock || block == Blocks.BUBBLE_COLUMN || block instanceof ShulkerBoxBlock || block instanceof SlabBlock || block instanceof TrapDoorBlock || block == Blocks.HONEY_BLOCK || block == Blocks.END_ROD || block == Blocks.SWEET_BERRY_BUSH || block == Blocks.POINTED_DRIPSTONE || block instanceof AmethystClusterBlock || block instanceof AzaleaBlock) { + return NO; + } if (block == Blocks.BIG_DRIPLEAF) { - return false; + return NO; } if (block == Blocks.POWDER_SNOW) { - return false; + return NO; } if (Baritone.settings().blocksToAvoid.value.contains(block)) { - return false; + return NO; } if (block instanceof DoorBlock || block instanceof FenceGateBlock) { - // Because there's no nice method in vanilla to check if a door is openable or not, we just have to assume - // that anything that isn't an iron door isn't openable, ignoring that some doors introduced in mods can't - // be opened by just interacting. - return block != Blocks.IRON_DOOR; + // TODO this assumes that all doors in all mods are openable + if (block == Blocks.IRON_DOOR) { + return NO; + } + return YES; } - if (block instanceof WoolCarpetBlock) { - return canWalkOn(bsi, x, y - 1, z); + if (block instanceof CarpetBlock) { + return MAYBE; } if (block instanceof SnowLayerBlock) { - // we've already checked doors and fence gates - // so the only remaining dynamic isPassables are snow and trapdoor + // snow layers cached as the top layer of a packed chunk have no metadata, we can't make a decision based on their depth here + // it would otherwise make long distance pathing through snowy biomes impossible + return MAYBE; + } + FluidState fluidState = state.getFluidState(); + if (!fluidState.isEmpty()) { + if (fluidState.getType().getAmount(fluidState) != 8) { + return NO; + } else { + return MAYBE; + } + } + if (block instanceof CauldronBlock) { + return NO; + } + try { // A dodgy catch-all at the end, for most blocks with default behaviour this will work, however where blocks are special this will error out, and we can handle it when we have this information + if (state.isPathfindable(null, null, PathComputationType.LAND)) { + return YES; + } else { + return NO; + } + } catch (Throwable exception) { + System.out.println("The block " + state.getBlock().getName().getString() + " requires a special case due to the exception " + exception.getMessage()); + return MAYBE; + } + } + + static boolean canWalkThroughPosition(BlockStateInterface bsi, int x, int y, int z, BlockState state) { + Block block = state.getBlock(); + + if (block instanceof CarpetBlock) { + return canWalkOn(bsi, x, y - 1, z); + } + + if (block instanceof SnowLayerBlock) { // if they're cached as a top block, we don't know their metadata // default to true (mostly because it would otherwise make long distance pathing through snowy biomes impossible) if (!bsi.worldContainsLoadedChunk(x, z)) { @@ -140,55 +212,33 @@ public interface MovementHelper extends ActionCosts, Helper { return canWalkOn(bsi, x, y - 1, z); } - if (isFlowing(x, y, z, state, bsi)) { - return false; // Don't walk through flowing liquids - } FluidState fluidState = state.getFluidState(); - if (fluidState.getType() instanceof WaterFluid) { + if (!fluidState.isEmpty()) { + if (isFlowing(x, y, z, state, bsi)) { + return false; + } + // Everything after this point has to be a special case as it relies on the water not being flowing, which means a special case is needed. if (Baritone.settings().assumeWalkOnWater.value) { return false; } + BlockState up = bsi.get0(x, y + 1, z); if (!up.getFluidState().isEmpty() || up.getBlock() instanceof WaterlilyBlock) { return false; } - return true; - } - if (block instanceof CauldronBlock) { - return false; + return fluidState.getType() instanceof WaterFluid; } + // every block that overrides isPassable with anything more complicated than a "return true;" or "return false;" // has already been accounted for above // therefore it's safe to not construct a blockpos from our x, y, z ints and instead just pass null return state.isPathfindable(bsi.access, BlockPos.ZERO, PathComputationType.LAND); // workaround for future compatibility =P } - /** - * canWalkThrough but also won't impede movement at all. so not including doors or fence gates (we'd have to right click), - * not including water, and not including ladders or vines or cobwebs (they slow us down) - * - * @param context Calculation context to provide block state lookup - * @param x The block's x position - * @param y The block's y position - * @param z The block's z position - * @return Whether or not the block at the specified position - */ - static boolean fullyPassable(CalculationContext context, int x, int y, int z) { - return fullyPassable( - context.bsi.access, - context.bsi.isPassableBlockPos.set(x, y, z), - context.bsi.get0(x, y, z) - ); - } - - static boolean fullyPassable(IPlayerContext ctx, BlockPos pos) { - return fullyPassable(ctx.world(), pos, ctx.world().getBlockState(pos)); - } - - static boolean fullyPassable(BlockGetter access, BlockPos pos, BlockState state) { + static Ternary fullyPassableBlockState(BlockState state) { Block block = state.getBlock(); if (block instanceof AirBlock) { // early return for most common case - return true; + return YES; } // exceptions - blocks that are isPassable true, but we can't actually jump through if (block instanceof BaseFireBlock @@ -206,10 +256,49 @@ public interface MovementHelper extends ActionCosts, Helper { || block instanceof EndPortalBlock || block instanceof SkullBlock || block instanceof ShulkerBoxBlock) { - return false; + return NO; } // door, fence gate, liquid, trapdoor have been accounted for, nothing else uses the world or pos parameters - return state.isPathfindable(access, pos, PathComputationType.LAND); + // at least in 1.12.2 vanilla, that is..... + try { // A dodgy catch-all at the end, for most blocks with default behaviour this will work, however where blocks are special this will error out, and we can handle it when we have this information + if (state.isPathfindable(null, null, PathComputationType.LAND)) { + return YES; + } else { + return NO; + } + } catch (Throwable exception) { + // see PR #1087 for why + System.out.println("The block " + state.getBlock().getName().getString() + " requires a special case due to the exception " + exception.getMessage()); + return MAYBE; + } + } + + /** + * canWalkThrough but also won't impede movement at all. so not including doors or fence gates (we'd have to right click), + * not including water, and not including ladders or vines or cobwebs (they slow us down) + */ + static boolean fullyPassable(CalculationContext context, int x, int y, int z) { + return fullyPassable(context, x, y, z, context.get(x, y, z)); + } + + static boolean fullyPassable(CalculationContext context, int x, int y, int z, BlockState state) { + return context.precomputedData.fullyPassable(context.bsi, x, y, z, state); + } + + static boolean fullyPassable(IPlayerContext ctx, BlockPos pos) { + BlockState state = ctx.world().getBlockState(pos); + Ternary fullyPassable = fullyPassableBlockState(state); + if (fullyPassable == YES) { + return true; + } + if (fullyPassable == NO) { + return false; + } + return fullyPassablePosition(new BlockStateInterface(ctx), pos.getX(), pos.getY(), pos.getZ(), state); // meh + } + + static boolean fullyPassablePosition(BlockStateInterface bsi, int x, int y, int z, BlockState state) { + return state.isPathfindable(bsi.access, bsi.isPassableBlockPos.set(x, y, z), PathComputationType.LAND); } static boolean isReplaceable(int x, int y, int z, BlockState state, BlockStateInterface bsi) { @@ -308,6 +397,8 @@ public interface MovementHelper extends ActionCosts, Helper { * Can I walk on this block without anything weird happening like me falling * through? Includes water because we know that we automatically jump on * water + *

+ * If changing something in this function remember to also change it in precomputed data * * @param bsi Block state provider * @param x The block's x position @@ -317,36 +408,68 @@ public interface MovementHelper extends ActionCosts, Helper { * @return Whether or not the specified block can be walked on */ static boolean canWalkOn(BlockStateInterface bsi, int x, int y, int z, BlockState state) { - Block block = state.getBlock(); - if (block instanceof AirBlock || block == Blocks.MAGMA_BLOCK || block == Blocks.BUBBLE_COLUMN || block == Blocks.HONEY_BLOCK) { - // early return for most common case (air) - // plus magma, which is a normal cube but it hurts you + Ternary canWalkOn = canWalkOnBlockState(state); + if (canWalkOn == YES) { + return true; + } + if (canWalkOn == NO) { return false; } - if (isBlockNormalCube(state)) { - return true; + return canWalkOnPosition(bsi, x, y, z, state); + } + + static Ternary canWalkOnBlockState(BlockState state) { + Block block = state.getBlock(); + if (isBlockNormalCube(state) && block != Blocks.MAGMA_BLOCK && block != Blocks.BUBBLE_COLUMN && block != Blocks.HONEY_BLOCK) { + return YES; } if (block instanceof AzaleaBlock) { - return true; + return YES; } if (block == Blocks.LADDER || (block == Blocks.VINE && Baritone.settings().allowVines.value)) { // TODO reconsider this - return true; + return YES; } if (block == Blocks.FARMLAND || block == Blocks.DIRT_PATH) { - return true; + return YES; } if (block == Blocks.ENDER_CHEST || block == Blocks.CHEST || block == Blocks.TRAPPED_CHEST) { - return true; + return YES; } + if (block == Blocks.GLASS || block instanceof StainedGlassBlock) { + return YES; + } + if (block instanceof StairBlock) { + return YES; + } + if (isWater(state)) { + return MAYBE; + } + if (MovementHelper.isLava(state) && Baritone.settings().assumeWalkOnLava.value) { + return MAYBE; + } + if (block instanceof SlabBlock) { + if (!Baritone.settings().allowWalkOnBottomSlab.value) { + if (state.getValue(SlabBlock.TYPE) != SlabType.BOTTOM) { + return YES; + } + return NO; + } + return YES; + } + return NO; + } + + static boolean canWalkOnPosition(BlockStateInterface bsi, int x, int y, int z, BlockState state) { + Block block = state.getBlock(); if (isWater(state)) { // since this is called literally millions of times per second, the benefit of not allocating millions of useless "pos.up()" // BlockPos s that we'd just garbage collect immediately is actually noticeable. I don't even think its a decrease in readability BlockState upState = bsi.get0(x, y + 1, z); Block up = upState.getBlock(); - if (up == Blocks.LILY_PAD || up instanceof WoolCarpetBlock) { + if (up == Blocks.LILY_PAD || up instanceof CarpetBlock) { return true; } - if (isFlowing(x, y, z, state, bsi) || upState.getFluidState().getType() == Fluids.FLOWING_WATER) { + if (MovementHelper.isFlowing(x, y, z, state, bsi) || upState.getFluidState().getType() == Fluids.FLOWING_WATER) { // the only scenario in which we can walk on flowing water is if it's under still water with jesus off return isWater(upState) && !Baritone.settings().assumeWalkOnWater.value; } @@ -354,19 +477,20 @@ public interface MovementHelper extends ActionCosts, Helper { // if assumeWalkOnWater is off, we can only walk on water if there is water above it return isWater(upState) ^ Baritone.settings().assumeWalkOnWater.value; } - if (Baritone.settings().assumeWalkOnLava.value && isLava(state) && !isFlowing(x, y, z, state, bsi)) { + + if (MovementHelper.isLava(state) && !MovementHelper.isFlowing(x, y, z, state, bsi) && Baritone.settings().assumeWalkOnLava.value) { // if we get here it means that assumeWalkOnLava must be true, so put it last return true; } - if (block == Blocks.GLASS || block instanceof StainedGlassBlock) { - return true; - } - if (block instanceof SlabBlock) { - if (!Baritone.settings().allowWalkOnBottomSlab.value) { - return state.getValue(SlabBlock.TYPE) != SlabType.BOTTOM; - } - return true; - } - return block instanceof StairBlock; + + return false; // If we don't recognise it then we want to just return false to be safe. + } + + static boolean canWalkOn(CalculationContext context, int x, int y, int z, BlockState state) { + return context.precomputedData.canWalkOn(context.bsi, x, y, z, state); + } + + static boolean canWalkOn(CalculationContext context, int x, int y, int z) { + return canWalkOn(context, x, y, z, context.get(x, y, z)); } static boolean canWalkOn(IPlayerContext ctx, BetterBlockPos pos, BlockState state) { @@ -385,6 +509,60 @@ public interface MovementHelper extends ActionCosts, Helper { return canWalkOn(bsi, x, y, z, bsi.get0(x, y, z)); } + static boolean canUseFrostWalker(CalculationContext context, BlockState state) { + return context.frostWalker != 0 + && state.getMaterial() == Material.WATER + && ((Integer) state.getValue(LiquidBlock.LEVEL)) == 0; + } + + static boolean canUseFrostWalker(IPlayerContext ctx, BlockPos pos) { + BlockState state = BlockStateInterface.get(ctx, pos); + return EnchantmentHelper.hasFrostWalker(ctx.player()) + && state.getMaterial() == Material.WATER + && ((Integer) state.getValue(LiquidBlock.LEVEL)) == 0; + } + + /** + * If movements make us stand/walk on this block, will it have a top to walk on? + */ + static boolean mustBeSolidToWalkOn(CalculationContext context, int x, int y, int z, BlockState state) { + Block block = state.getBlock(); + if (block == Blocks.LADDER || block == Blocks.VINE) { + return false; + } + if (!state.getFluidState().isEmpty()) { + // used for frostwalker so only includes blocks where we are still on ground when leaving them to any side + // TODO 1.19+ : add leaves, add dripleaf? + if (block instanceof SlabBlock) { + if (state.getValue(SlabBlock.TYPE) != SlabType.BOTTOM) { + return true; + } + } else if (block instanceof StairBlock) { + if (state.getValue(StairBlock.HALF) == Half.TOP) { + return true; + } + StairsShape shape = state.getValue(StairBlock.SHAPE); + if (shape == StairsShape.INNER_LEFT || shape == StairsShape.INNER_RIGHT) { + return true; + } + } else if (block instanceof TrapDoorBlock) { + if (!state.getValue(TrapDoorBlock.OPEN) && state.getValue(TrapDoorBlock.HALF) == Half.TOP) { + return true; + } + } else if (block == Blocks.SCAFFOLDING) { + return true; + } + if (context.assumeWalkOnWater) { + return false; + } + Block blockAbove = context.getBlock(x, y + 1, z); + if (blockAbove instanceof LiquidBlock) { + return false; + } + } + return true; + } + static boolean canPlaceAgainst(BlockStateInterface bsi, int x, int y, int z) { return canPlaceAgainst(bsi, x, y, z, bsi.get0(x, y, z)); } @@ -413,7 +591,7 @@ public interface MovementHelper extends ActionCosts, Helper { static double getMiningDurationTicks(CalculationContext context, int x, int y, int z, BlockState state, boolean includeFalling) { Block block = state.getBlock(); - if (!canWalkThrough(context.bsi, x, y, z, state)) { + if (!canWalkThrough(context, x, y, z, state)) { if (!state.getFluidState().isEmpty()) { return COST_INF; } diff --git a/src/main/java/baritone/pathing/movement/movements/MovementAscend.java b/src/main/java/baritone/pathing/movement/movements/MovementAscend.java index fa70b6ddd..717cd2e70 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementAscend.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementAscend.java @@ -67,7 +67,7 @@ public class MovementAscend extends Movement { public static double cost(CalculationContext context, int x, int y, int z, int destX, int destZ) { BlockState toPlace = context.get(destX, y, destZ); double additionalPlacementCost = 0; - if (!MovementHelper.canWalkOn(context.bsi, destX, y, destZ, toPlace)) { + if (!MovementHelper.canWalkOn(context, destX, y, destZ, toPlace)) { additionalPlacementCost = context.costOfPlacingAt(destX, y, destZ, toPlace); if (additionalPlacementCost >= COST_INF) { return COST_INF; @@ -93,7 +93,7 @@ public class MovementAscend extends Movement { } } BlockState srcUp2 = context.get(x, y + 2, z); // used lower down anyway - if (context.get(x, y + 3, z).getBlock() instanceof FallingBlock && (MovementHelper.canWalkThrough(context.bsi, x, y + 1, z) || !(srcUp2.getBlock() instanceof FallingBlock))) {//it would fall on us and possibly suffocate us + if (context.get(x, y + 3, z).getBlock() instanceof FallingBlock && (MovementHelper.canWalkThrough(context, x, y + 1, z) || !(srcUp2.getBlock() instanceof FallingBlock))) {//it would fall on us and possibly suffocate us // HOWEVER, we assume that we're standing in the start position // that means that src and src.up(1) are both air // maybe they aren't now, but they will be by the time this starts diff --git a/src/main/java/baritone/pathing/movement/movements/MovementDescend.java b/src/main/java/baritone/pathing/movement/movements/MovementDescend.java index 7024e28b9..ec069ae4f 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementDescend.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementDescend.java @@ -42,6 +42,7 @@ import net.minecraft.world.phys.Vec3; public class MovementDescend extends Movement { private int numTicks = 0; + public boolean forceSafeMode = false; public MovementDescend(IBaritone baritone, BetterBlockPos start, BetterBlockPos end) { super(baritone, start, end, new BetterBlockPos[]{end.above(2), end.above(), end}, end.below()); @@ -51,6 +52,14 @@ public class MovementDescend extends Movement { public void reset() { super.reset(); numTicks = 0; + forceSafeMode = false; + } + + /** + * Called by PathExecutor if needing safeMode can only be detected with knowledge about the next movement + */ + public void forceSafeMode() { + forceSafeMode = true; } @Override @@ -100,7 +109,7 @@ public class MovementDescend extends Movement { //C, D, etc determine the length of the fall BlockState below = context.get(destX, y - 2, destZ); - if (!MovementHelper.canWalkOn(context.bsi, destX, y - 2, destZ, below)) { + if (!MovementHelper.canWalkOn(context, destX, y - 2, destZ, below)) { dynamicFallCost(context, x, y, z, destX, destZ, totalCost, below, res); return; } @@ -108,6 +117,9 @@ public class MovementDescend extends Movement { if (destDown.getBlock() == Blocks.LADDER || destDown.getBlock() == Blocks.VINE) { return; } + if (MovementHelper.canUseFrostWalker(context, destDown)) { // no need to check assumeWalkOnWater + return; // the water will freeze when we try to walk into it + } // we walk half the block plus 0.3 to get to the edge, then we walk the other 0.2 while simultaneously falling (math.max because of how it's in parallel) double walk = WALK_OFF_BLOCK_COST; @@ -129,7 +141,7 @@ public class MovementDescend extends Movement { // and potentially replace the water we're going to fall into return false; } - if (!MovementHelper.canWalkThrough(context.bsi, destX, y - 2, destZ, below)) { + if (!MovementHelper.canWalkThrough(context, destX, y - 2, destZ, below)) { return false; } double costSoFar = 0; @@ -145,7 +157,7 @@ public class MovementDescend extends Movement { int unprotectedFallHeight = fallHeight - (y - effectiveStartHeight); // equal to fallHeight - y + effectiveFallHeight, which is equal to -newY + effectiveFallHeight, which is equal to effectiveFallHeight - newY double tentativeCost = WALK_OFF_BLOCK_COST + FALL_N_BLOCKS_COST[unprotectedFallHeight] + frontBreak + costSoFar; if (MovementHelper.isWater(ontoBlock)) { - if (!MovementHelper.canWalkThrough(context.bsi, destX, newY, destZ, ontoBlock)) { + if (!MovementHelper.canWalkThrough(context, destX, newY, destZ, ontoBlock)) { return false; } if (context.assumeWalkOnWater) { @@ -154,7 +166,7 @@ public class MovementDescend extends Movement { if (MovementHelper.isFlowing(destX, newY, destZ, ontoBlock, context.bsi)) { return false; // TODO flowing check required here? } - if (!MovementHelper.canWalkOn(context.bsi, destX, newY - 1, destZ)) { + if (!MovementHelper.canWalkOn(context, destX, newY - 1, destZ)) { // we could punch right through the water into something else return false; } @@ -173,10 +185,10 @@ public class MovementDescend extends Movement { effectiveStartHeight = newY; continue; } - if (MovementHelper.canWalkThrough(context.bsi, destX, newY, destZ, ontoBlock)) { + if (MovementHelper.canWalkThrough(context, destX, newY, destZ, ontoBlock)) { continue; } - if (!MovementHelper.canWalkOn(context.bsi, destX, newY, destZ, ontoBlock)) { + if (!MovementHelper.canWalkOn(context, destX, newY, destZ, ontoBlock)) { return false; } if (MovementHelper.isBottomSlab(ontoBlock)) { @@ -247,6 +259,9 @@ public class MovementDescend extends Movement { } public boolean safeMode() { + if (forceSafeMode) { + return true; + } // (dest - src) + dest is offset 1 more in the same direction // so it's the block we'd need to worry about running into if we decide to sprint straight through this descend BlockPos into = dest.subtract(src.below()).offset(dest); diff --git a/src/main/java/baritone/pathing/movement/movements/MovementDiagonal.java b/src/main/java/baritone/pathing/movement/movements/MovementDiagonal.java index fc3fa2f45..cf387d5c9 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementDiagonal.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementDiagonal.java @@ -59,7 +59,7 @@ public class MovementDiagonal extends Movement { @Override protected boolean safeToCancel(MovementState state) { //too simple. backfill does not work after cornering with this - //return MovementHelper.canWalkOn(ctx, ctx.playerFeet().down()); + //return context.precomputedData.canWalkOn(ctx, ctx.playerFeet().down()); LocalPlayer player = ctx.player(); double offset = 0.25; double x = player.position().x; @@ -109,40 +109,49 @@ public class MovementDiagonal extends Movement { } public static void cost(CalculationContext context, int x, int y, int z, int destX, int destZ, MutableMoveResult res) { - if (!MovementHelper.canWalkThrough(context.bsi, destX, y + 1, destZ)) { + if (!MovementHelper.canWalkThrough(context, destX, y + 1, destZ)) { return; } BlockState destInto = context.get(destX, y, destZ); + BlockState fromDown; boolean ascend = false; BlockState destWalkOn; boolean descend = false; - if (!MovementHelper.canWalkThrough(context.bsi, destX, y, destZ, destInto)) { + boolean frostWalker = false; + if (!MovementHelper.canWalkThrough(context, destX, y, destZ, destInto)) { ascend = true; - if (!context.allowDiagonalAscend || !MovementHelper.canWalkThrough(context.bsi, x, y + 2, z) || !MovementHelper.canWalkOn(context.bsi, destX, y, destZ, destInto) || !MovementHelper.canWalkThrough(context.bsi, destX, y + 2, destZ)) { + if (!context.allowDiagonalAscend || !MovementHelper.canWalkThrough(context, x, y + 2, z) || !MovementHelper.canWalkOn(context, destX, y, destZ, destInto) || !MovementHelper.canWalkThrough(context, destX, y + 2, destZ)) { return; } destWalkOn = destInto; + fromDown = context.get(x, y - 1, z); } else { destWalkOn = context.get(destX, y - 1, destZ); - if (!MovementHelper.canWalkOn(context.bsi, destX, y - 1, destZ, destWalkOn)) { + fromDown = context.get(x, y - 1, z); + boolean standingOnABlock = MovementHelper.mustBeSolidToWalkOn(context, x, y - 1, z, fromDown); + frostWalker = standingOnABlock && MovementHelper.canUseFrostWalker(context, destWalkOn); + if (!frostWalker && !MovementHelper.canWalkOn(context, destX, y - 1, destZ, destWalkOn)) { descend = true; - if (!context.allowDiagonalDescend || !MovementHelper.canWalkOn(context.bsi, destX, y - 2, destZ) || !MovementHelper.canWalkThrough(context.bsi, destX, y - 1, destZ, destWalkOn)) { + if (!context.allowDiagonalDescend || !MovementHelper.canWalkOn(context, destX, y - 2, destZ) || !MovementHelper.canWalkThrough(context, destX, y - 1, destZ, destWalkOn)) { return; } } + frostWalker &= !context.assumeWalkOnWater; // do this after checking for descends because jesus can't prevent the water from freezing, it just prevents us from relying on the water freezing } double multiplier = WALK_ONE_BLOCK_COST; // For either possible soul sand, that affects half of our walking if (destWalkOn.getBlock() == Blocks.SOUL_SAND) { multiplier += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2; + } else if (frostWalker) { + // frostwalker lets us walk on water without the penalty } else if (destWalkOn.getBlock() == Blocks.WATER) { multiplier += context.walkOnWaterOnePenalty * SQRT_2; } - Block fromDown = context.get(x, y - 1, z).getBlock(); - if (fromDown == Blocks.LADDER || fromDown == Blocks.VINE) { + Block fromDownBlock = fromDown.getBlock(); + if (fromDownBlock == Blocks.LADDER || fromDownBlock == Blocks.VINE) { return; } - if (fromDown == Blocks.SOUL_SAND) { + if (fromDownBlock == Blocks.SOUL_SAND) { multiplier += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2; } BlockState cuttingOver1 = context.get(x, y - 1, destZ); @@ -169,17 +178,17 @@ public class MovementDiagonal extends Movement { BlockState pb0 = context.get(x, y, destZ); BlockState pb2 = context.get(destX, y, z); if (ascend) { - boolean ATop = MovementHelper.canWalkThrough(context.bsi, x, y + 2, destZ); - boolean AMid = MovementHelper.canWalkThrough(context.bsi, x, y + 1, destZ); - boolean ALow = MovementHelper.canWalkThrough(context.bsi, x, y, destZ, pb0); - boolean BTop = MovementHelper.canWalkThrough(context.bsi, destX, y + 2, z); - boolean BMid = MovementHelper.canWalkThrough(context.bsi, destX, y + 1, z); - boolean BLow = MovementHelper.canWalkThrough(context.bsi, destX, y, z, pb2); + boolean ATop = MovementHelper.canWalkThrough(context, x, y + 2, destZ); + boolean AMid = MovementHelper.canWalkThrough(context, x, y + 1, destZ); + boolean ALow = MovementHelper.canWalkThrough(context, x, y, destZ, pb0); + boolean BTop = MovementHelper.canWalkThrough(context, destX, y + 2, z); + boolean BMid = MovementHelper.canWalkThrough(context, destX, y + 1, z); + boolean BLow = MovementHelper.canWalkThrough(context, destX, y, z, pb2); if ((!(ATop && AMid && ALow) && !(BTop && BMid && BLow)) // no option || MovementHelper.avoidWalkingInto(pb0) // bad || MovementHelper.avoidWalkingInto(pb2) // bad - || (ATop && AMid && MovementHelper.canWalkOn(context.bsi, x, y, destZ, pb0)) // we could just ascend - || (BTop && BMid && MovementHelper.canWalkOn(context.bsi, destX, y, z, pb2)) // we could just ascend + || (ATop && AMid && MovementHelper.canWalkOn(context, x, y, destZ, pb0)) // we could just ascend + || (BTop && BMid && MovementHelper.canWalkOn(context, destX, y, z, pb2)) // we could just ascend || (!ATop && AMid && ALow) // head bonk A || (!BTop && BMid && BLow)) { // head bonk B return; diff --git a/src/main/java/baritone/pathing/movement/movements/MovementDownward.java b/src/main/java/baritone/pathing/movement/movements/MovementDownward.java index 474886c5f..a37df38b6 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementDownward.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementDownward.java @@ -58,7 +58,7 @@ public class MovementDownward extends Movement { if (!context.allowDownward) { return COST_INF; } - if (!MovementHelper.canWalkOn(context.bsi, x, y - 2, z)) { + if (!MovementHelper.canWalkOn(context, x, y - 2, z)) { return COST_INF; } BlockState down = context.get(x, y - 1, z); diff --git a/src/main/java/baritone/pathing/movement/movements/MovementParkour.java b/src/main/java/baritone/pathing/movement/movements/MovementParkour.java index 7002bb3ac..c46cf68bd 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementParkour.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementParkour.java @@ -17,6 +17,7 @@ package baritone.pathing.movement.movements; +import baritone.Baritone; import baritone.api.IBaritone; import baritone.api.pathing.movement.MovementStatus; import baritone.api.utils.BetterBlockPos; @@ -27,16 +28,16 @@ import baritone.pathing.movement.MovementHelper; import baritone.pathing.movement.MovementState; import baritone.utils.BlockStateInterface; import baritone.utils.pathing.MutableMoveResult; -import java.util.HashSet; -import java.util.Set; import net.minecraft.core.Direction; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.StairBlock; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.material.Fluids; import net.minecraft.world.level.material.WaterFluid; +import java.util.HashSet; +import java.util.Set; + public class MovementParkour extends Movement { private static final BetterBlockPos[] EMPTY = new BetterBlockPos[]{}; @@ -74,7 +75,7 @@ public class MovementParkour extends Movement { return; } BlockState adj = context.get(x + xDiff, y - 1, z + zDiff); - if (MovementHelper.canWalkOn(context.bsi, x + xDiff, y - 1, z + zDiff, adj)) { // don't parkour if we could just traverse (for now) + if (MovementHelper.canWalkOn(context, x + xDiff, y - 1, z + zDiff, adj)) { // don't parkour if we could just traverse (for now) // second most common case -- we could just traverse not parkour return; } @@ -91,9 +92,16 @@ public class MovementParkour extends Movement { return; } BlockState standingOn = context.get(x, y - 1, z); - if (standingOn.getBlock() == Blocks.VINE || standingOn.getBlock() == Blocks.LADDER || standingOn.getBlock() instanceof StairBlock || MovementHelper.isBottomSlab(standingOn) || standingOn.getFluidState().getType() != Fluids.EMPTY) { + if (standingOn.getBlock() == Blocks.VINE || standingOn.getBlock() == Blocks.LADDER || standingOn.getBlock() instanceof StairBlock || MovementHelper.isBottomSlab(standingOn)) { return; } + // we can't jump from (frozen) water with assumeWalkOnWater because we can't be sure it will be frozen + if (context.assumeWalkOnWater && !standingOn.getFluidState().isEmpty()) { + return; + } + if (!context.get(x, y, z).getFluidState().isEmpty()) { + return; // can't jump out of water + } int maxJump; if (standingOn.getBlock() == Blocks.SOUL_SAND) { maxJump = 2; // 1 block gap @@ -104,13 +112,13 @@ public class MovementParkour extends Movement { maxJump = 3; } } - + // check parkour jumps from smallest to largest for obstacles/walls and landing positions int verifiedMaxJump = 1; // i - 1 (when i = 2) for (int i = 2; i <= maxJump; i++) { int destX = x + xDiff * i; int destZ = z + zDiff * i; - + // check head/feet if (!MovementHelper.fullyPassable(context, destX, y + 1, destZ)) { break; @@ -118,11 +126,11 @@ public class MovementParkour extends Movement { if (!MovementHelper.fullyPassable(context, destX, y + 2, destZ)) { break; } - + // check for ascend landing position BlockState destInto = context.bsi.get0(destX, y, destZ); - if (!MovementHelper.fullyPassable(context.bsi.access, context.bsi.isPassableBlockPos.set(destX, y, destZ), destInto)) { - if (i <= 3 && context.allowParkourAscend && context.canSprint && MovementHelper.canWalkOn(context.bsi, destX, y, destZ, destInto) && checkOvershootSafety(context.bsi, destX + xDiff, y + 1, destZ + zDiff)) { + if (!MovementHelper.fullyPassable(context, destX, y, destZ, destInto)) { + if (i <= 3 && context.allowParkourAscend && context.canSprint && MovementHelper.canWalkOn(context, destX, y, destZ, destInto) && checkOvershootSafety(context.bsi, destX + xDiff, y + 1, destZ + zDiff)) { res.x = destX; res.y = y + 1; res.z = destZ; @@ -131,11 +139,14 @@ public class MovementParkour extends Movement { } break; } - + // check for flat landing position BlockState landingOn = context.bsi.get0(destX, y - 1, destZ); // farmland needs to be canWalkOn otherwise farm can never work at all, but we want to specifically disallow ending a jump on farmland haha - if (landingOn.getBlock() != Blocks.FARMLAND && MovementHelper.canWalkOn(context.bsi, destX, y - 1, destZ, landingOn)) { + // frostwalker works here because we can't jump from possibly unfrozen water + if ((landingOn.getBlock() != Blocks.FARMLAND && MovementHelper.canWalkOn(context, destX, y - 1, destZ, landingOn)) + || (Math.min(16, context.frostWalker + 2) >= i && MovementHelper.canUseFrostWalker(context, landingOn)) + ) { if (checkOvershootSafety(context.bsi, destX + xDiff, y, destZ + zDiff)) { res.x = destX; res.y = y; @@ -145,14 +156,14 @@ public class MovementParkour extends Movement { } break; } - + if (!MovementHelper.fullyPassable(context, destX, y + 3, destZ)) { break; } - + verifiedMaxJump = i; } - + // parkour place starts here if (!context.allowParkourPlace) { return; @@ -265,7 +276,12 @@ public class MovementParkour extends Movement { } } else if (!ctx.playerFeet().equals(src)) { if (ctx.playerFeet().equals(src.relative(direction)) || ctx.player().position().y - src.y > 0.0001) { - if (!MovementHelper.canWalkOn(ctx, dest.below()) && !ctx.player().isOnGround() && MovementHelper.attemptToPlaceABlock(state, baritone, dest.below(), true, false) == PlaceResult.READY_TO_PLACE) { + if (Baritone.settings().allowPlace.value // see PR #3775 + && ((Baritone) baritone).getInventoryBehavior().hasGenericThrowaway() + && !MovementHelper.canWalkOn(ctx, dest.below()) + && !ctx.player().isOnGround() + && MovementHelper.attemptToPlaceABlock(state, baritone, dest.below(), true, false) == PlaceResult.READY_TO_PLACE + ) { // go in the opposite order to check DOWN before all horizontals -- down is preferable because you don't have to look to the side while in midair, which could mess up the trajectory state.setInput(Input.CLICK_RIGHT, true); } diff --git a/src/main/java/baritone/pathing/movement/movements/MovementPillar.java b/src/main/java/baritone/pathing/movement/movements/MovementPillar.java index 9b775b973..cf084093c 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementPillar.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementPillar.java @@ -35,6 +35,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.world.level.block.AirBlock; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.CarpetBlock; import net.minecraft.world.level.block.FallingBlock; import net.minecraft.world.level.block.FenceGateBlock; import net.minecraft.world.level.block.LadderBlock; @@ -42,6 +43,7 @@ import net.minecraft.world.level.block.SlabBlock; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.SlabType; import net.minecraft.world.phys.Vec3; + import java.util.Set; public class MovementPillar extends Movement { @@ -105,6 +107,10 @@ public class MovementPillar extends Movement { // if we're standing on water and assumeWalkOnWater is false, we must have ascended to here, or sneak backplaced, so it is possible to pillar again return COST_INF; } + if ((from == Blocks.LILY_PAD || from instanceof CarpetBlock) && !fromDown.getFluidState().isEmpty()) { + // to ascend here we'd have to break the block we are standing on + return COST_INF; + } double hardness = MovementHelper.getMiningDurationTicks(context, x, y + 2, z, toBreak, true); if (hardness >= COST_INF) { return COST_INF; @@ -124,7 +130,7 @@ public class MovementPillar extends Movement { } } // this is commented because it may have had a purpose, but it's very unclear what it was. it's from the minebot era. - //if (!MovementHelper.canWalkOn(chkPos, check) || MovementHelper.canWalkThrough(chkPos, check)) {//if the block above where we want to break is not a full block, don't do it + //if (!MovementHelper.canWalkOn(context, chkPos, check) || MovementHelper.canWalkThrough(context, chkPos, check)) {//if the block above where we want to break is not a full block, don't do it // TODO why does canWalkThrough mean this action is COST_INF? // FallingBlock makes sense, and !canWalkOn deals with weird cases like if it were lava // but I don't understand why canWalkThrough makes it impossible diff --git a/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java b/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java index 02426c46a..cec3ca39a 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java @@ -35,14 +35,15 @@ import net.minecraft.core.BlockPos; import net.minecraft.world.level.block.AirBlock; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.CarpetBlock; import net.minecraft.world.level.block.DoorBlock; import net.minecraft.world.level.block.FenceGateBlock; import net.minecraft.world.level.block.LadderBlock; import net.minecraft.world.level.block.SlabBlock; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.SlabType; -import net.minecraft.world.level.material.WaterFluid; import net.minecraft.world.phys.Vec3; + import java.util.Optional; import java.util.Set; @@ -77,9 +78,11 @@ public class MovementTraverse extends Movement { BlockState pb0 = context.get(destX, y + 1, destZ); BlockState pb1 = context.get(destX, y, destZ); BlockState destOn = context.get(destX, y - 1, destZ); - BlockState down = context.get(x, y - 1, z); - Block srcDown = down.getBlock(); - if (MovementHelper.canWalkOn(context.bsi, destX, y - 1, destZ, destOn)) {//this is a walk, not a bridge + BlockState srcDown = context.get(x, y - 1, z); + Block srcDownBlock = srcDown.getBlock(); + boolean standingOnABlock = MovementHelper.mustBeSolidToWalkOn(context, x, y - 1, z, srcDown); + boolean frostWalker = standingOnABlock && !context.assumeWalkOnWater && MovementHelper.canUseFrostWalker(context, destOn); + if (frostWalker || MovementHelper.canWalkOn(context, destX, y - 1, destZ, destOn)) { //this is a walk, not a bridge double WC = WALK_ONE_BLOCK_COST; boolean water = false; if (MovementHelper.isWater(pb0) || MovementHelper.isWater(pb1)) { @@ -88,10 +91,12 @@ public class MovementTraverse extends Movement { } else { if (destOn.getBlock() == Blocks.SOUL_SAND) { WC += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2; + } else if (frostWalker) { + // with frostwalker we can walk on water without the penalty, if we are sure we won't be using jesus } else if (destOn.getBlock() == Blocks.WATER) { WC += context.walkOnWaterOnePenalty; } - if (srcDown == Blocks.SOUL_SAND) { + if (srcDownBlock == Blocks.SOUL_SAND) { WC += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2; } } @@ -109,13 +114,13 @@ public class MovementTraverse extends Movement { } return WC; } - if (srcDown == Blocks.LADDER || srcDown == Blocks.VINE) { + if (srcDownBlock == Blocks.LADDER || srcDownBlock == Blocks.VINE) { hardness1 *= 5; hardness2 *= 5; } return WC + hardness1 + hardness2; } else {//this is a bridge, so we need to place a block - if (srcDown == Blocks.LADDER || srcDown == Blocks.VINE) { + if (srcDownBlock == Blocks.LADDER || srcDownBlock == Blocks.VINE) { return COST_INF; } if (MovementHelper.isReplaceable(destX, y - 1, destZ, destOn, context.bsi)) { @@ -146,12 +151,16 @@ public class MovementTraverse extends Movement { } } // now that we've checked all possible directions to side place, we actually need to backplace - if (srcDown == Blocks.SOUL_SAND || (srcDown instanceof SlabBlock && down.getValue(SlabBlock.TYPE) != SlabType.DOUBLE)) { + if (srcDownBlock == Blocks.SOUL_SAND || (srcDownBlock instanceof SlabBlock && srcDown.getValue(SlabBlock.TYPE) != SlabType.DOUBLE)) { return COST_INF; // can't sneak and backplace against soul sand or half slabs (regardless of whether it's top half or bottom half) =/ } - if (down.getFluidState().getType() instanceof WaterFluid) { + if (!standingOnABlock) { // standing on water / swimming return COST_INF; // this is obviously impossible } + Block blockSrc = context.getBlock(x, y, z); + if ((blockSrc == Blocks.LILY_PAD || blockSrc instanceof CarpetBlock) && !srcDown.getFluidState().isEmpty()) { + return COST_INF; // we can stand on these but can't place against them + } WC = WC * (SNEAK_ONE_BLOCK_COST / WALK_ONE_BLOCK_COST);//since we are sneak backplacing, we are sneaking lol return WC + placeCost + hardness1 + hardness2; } @@ -232,7 +241,7 @@ public class MovementTraverse extends Movement { } } - boolean isTheBridgeBlockThere = MovementHelper.canWalkOn(ctx, positionToPlace) || ladder; + boolean isTheBridgeBlockThere = MovementHelper.canWalkOn(ctx, positionToPlace) || ladder || MovementHelper.canUseFrostWalker(ctx, positionToPlace); BlockPos feet = ctx.playerFeet(); if (feet.getY() != dest.getY() && !ladder) { logDebug("Wrong Y coordinate"); diff --git a/src/main/java/baritone/pathing/path/PathExecutor.java b/src/main/java/baritone/pathing/path/PathExecutor.java index 6d1a26475..5c89da116 100644 --- a/src/main/java/baritone/pathing/path/PathExecutor.java +++ b/src/main/java/baritone/pathing/path/PathExecutor.java @@ -348,7 +348,7 @@ public class PathExecutor implements IPathExecutor, Helper { behavior.baritone.getInputOverrideHandler().setInputForceState(Input.SPRINT, false); // first and foremost, if allowSprint is off, or if we don't have enough hunger, don't try and sprint - if (!new CalculationContext(behavior.baritone).canSprint) { + if (!new CalculationContext(behavior.baritone, false).canSprint) { return false; } IMovement current = path.movements().get(pathPosition); @@ -378,6 +378,26 @@ public class PathExecutor implements IPathExecutor, Helper { // however, descend and ascend don't request sprinting, because they don't know the context of what movement comes after it if (current instanceof MovementDescend) { + if (pathPosition < path.length() - 2) { + // keep this out of onTick, even if that means a tick of delay before it has an effect + IMovement next = path.movements().get(pathPosition + 1); + if (MovementHelper.canUseFrostWalker(ctx, next.getDest().below())) { + // frostwalker only works if you cross the edge of the block on ground so in some cases we may not overshoot + // Since MovementDescend can't know the next movement we have to tell it + if (next instanceof MovementTraverse || next instanceof MovementParkour) { + boolean couldPlaceInstead = Baritone.settings().allowPlace.value && behavior.baritone.getInventoryBehavior().hasGenericThrowaway() && next instanceof MovementParkour; // traverse doesn't react fast enough + // this is true if the next movement does not ascend or descends and goes into the same cardinal direction (N-NE-E-SE-S-SW-W-NW) as the descend + // in that case current.getDirection() is e.g. (0, -1, 1) and next.getDirection() is e.g. (0, 0, 3) so the cross product of (0, 0, 1) and (0, 0, 3) is taken, which is (0, 0, 0) because the vectors are colinear (don't form a plane) + // since movements in exactly the opposite direction (e.g. descend (0, -1, 1) and traverse (0, 0, -1)) would also pass this check we also have to rule out that case + // we can do that by adding the directions because traverse is always 1 long like descend and parkour can't jump through current.getSrc().down() + boolean sameFlatDirection = !current.getDirection().above().offset(next.getDirection()).equals(BlockPos.ZERO) + && current.getDirection().above().cross(next.getDirection()).equals(BlockPos.ZERO); // here's why you learn maths in school + if (sameFlatDirection && !couldPlaceInstead) { + ((MovementDescend) current).forceSafeMode(); + } + } + } + } if (((MovementDescend) current).safeMode() && !((MovementDescend) current).skipToAscend()) { logDebug("Sprinting would be unsafe"); return false; diff --git a/src/main/java/baritone/pathing/precompute/PrecomputedData.java b/src/main/java/baritone/pathing/precompute/PrecomputedData.java new file mode 100644 index 000000000..9d7394254 --- /dev/null +++ b/src/main/java/baritone/pathing/precompute/PrecomputedData.java @@ -0,0 +1,117 @@ +/* + * 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.pathing.precompute; + +import baritone.pathing.movement.MovementHelper; +import baritone.utils.BlockStateInterface; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; + +import static baritone.pathing.precompute.Ternary.MAYBE; +import static baritone.pathing.precompute.Ternary.YES; + +public class PrecomputedData { + + private final int[] data = new int[Block.BLOCK_STATE_REGISTRY.size()]; + + private static final int COMPLETED_MASK = 1 << 0; + private static final int CAN_WALK_ON_MASK = 1 << 1; + private static final int CAN_WALK_ON_SPECIAL_MASK = 1 << 2; + private static final int CAN_WALK_THROUGH_MASK = 1 << 3; + private static final int CAN_WALK_THROUGH_SPECIAL_MASK = 1 << 4; + private static final int FULLY_PASSABLE_MASK = 1 << 5; + private static final int FULLY_PASSABLE_SPECIAL_MASK = 1 << 6; + + private int fillData(int id, BlockState state) { + int blockData = 0; + + Ternary canWalkOnState = MovementHelper.canWalkOnBlockState(state); + if (canWalkOnState == YES) { + blockData |= CAN_WALK_ON_MASK; + } + if (canWalkOnState == MAYBE) { + blockData |= CAN_WALK_ON_SPECIAL_MASK; + } + + Ternary canWalkThroughState = MovementHelper.canWalkThroughBlockState(state); + if (canWalkThroughState == YES) { + blockData |= CAN_WALK_THROUGH_MASK; + } + if (canWalkThroughState == MAYBE) { + blockData |= CAN_WALK_THROUGH_SPECIAL_MASK; + } + + Ternary fullyPassableState = MovementHelper.fullyPassableBlockState(state); + if (fullyPassableState == YES) { + blockData |= FULLY_PASSABLE_MASK; + } + if (fullyPassableState == MAYBE) { + blockData |= FULLY_PASSABLE_SPECIAL_MASK; + } + + blockData |= COMPLETED_MASK; + + data[id] = blockData; // in theory, this is thread "safe" because every thread should compute the exact same int to write? + return blockData; + } + + public boolean canWalkOn(BlockStateInterface bsi, int x, int y, int z, BlockState state) { + int id = Block.BLOCK_STATE_REGISTRY.getId(state); + int blockData = data[id]; + + if ((blockData & COMPLETED_MASK) == 0) { // we need to fill in the data + blockData = fillData(id, state); + } + + if ((blockData & CAN_WALK_ON_SPECIAL_MASK) != 0) { + return MovementHelper.canWalkOnPosition(bsi, x, y, z, state); + } else { + return (blockData & CAN_WALK_ON_MASK) != 0; + } + } + + public boolean canWalkThrough(BlockStateInterface bsi, int x, int y, int z, BlockState state) { + int id = Block.BLOCK_STATE_REGISTRY.getId(state); + int blockData = data[id]; + + if ((blockData & COMPLETED_MASK) == 0) { // we need to fill in the data + blockData = fillData(id, state); + } + + if ((blockData & CAN_WALK_THROUGH_SPECIAL_MASK) != 0) { + return MovementHelper.canWalkThroughPosition(bsi, x, y, z, state); + } else { + return (blockData & CAN_WALK_THROUGH_MASK) != 0; + } + } + + public boolean fullyPassable(BlockStateInterface bsi, int x, int y, int z, BlockState state) { + int id = Block.BLOCK_STATE_REGISTRY.getId(state); + int blockData = data[id]; + + if ((blockData & COMPLETED_MASK) == 0) { // we need to fill in the data + blockData = fillData(id, state); + } + + if ((blockData & FULLY_PASSABLE_SPECIAL_MASK) != 0) { + return MovementHelper.fullyPassablePosition(bsi, x, y, z, state); + } else { + return (blockData & FULLY_PASSABLE_MASK) != 0; + } + } +} diff --git a/src/main/java/baritone/utils/accessor/ILongArrayNBT.java b/src/main/java/baritone/pathing/precompute/Ternary.java similarity index 83% rename from src/main/java/baritone/utils/accessor/ILongArrayNBT.java rename to src/main/java/baritone/pathing/precompute/Ternary.java index df5ec72d0..d4d8424e0 100644 --- a/src/main/java/baritone/utils/accessor/ILongArrayNBT.java +++ b/src/main/java/baritone/pathing/precompute/Ternary.java @@ -15,13 +15,8 @@ * along with Baritone. If not, see . */ -package baritone.utils.accessor; +package baritone.pathing.precompute; -/** - * @author rycbar - * @since 26.09.2022 - */ -public interface ILongArrayNBT { - - long[] getLongArray(); -} \ No newline at end of file +public enum Ternary { + YES, MAYBE, NO +} diff --git a/src/main/java/baritone/process/BuilderProcess.java b/src/main/java/baritone/process/BuilderProcess.java index d83ef9c39..01eac45c1 100644 --- a/src/main/java/baritone/process/BuilderProcess.java +++ b/src/main/java/baritone/process/BuilderProcess.java @@ -74,6 +74,7 @@ import java.io.FileInputStream; import java.nio.file.Files; import java.util.*; import java.util.stream.Collectors; +import java.util.stream.Stream; import static baritone.api.pathing.movement.ActionCosts.COST_INF; @@ -90,6 +91,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil private int layer; private int numRepeats; private List approxPlaceable; + public int stopAtHeight = 0; public BuilderProcess(Baritone baritone) { super(baritone); @@ -100,6 +102,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil this.name = name; this.schematic = schematic; this.realSchematic = null; + boolean buildingSelectionSchematic = schematic instanceof SelectionSchematic; if (!Baritone.settings().buildSubstitutes.value.isEmpty()) { this.schematic = new SubstituteSchematic(this.schematic, Baritone.settings().buildSubstitutes.value); } @@ -118,6 +121,25 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil this.origin = new Vec3i(x, y, z); this.paused = false; this.layer = Baritone.settings().startAtLayer.value; + this.stopAtHeight = schematic.heightY(); + if (Baritone.settings().buildOnlySelection.value && buildingSelectionSchematic) { // currently redundant but safer maybe + if (baritone.getSelectionManager().getSelections().length == 0) { + logDirect("Poor little kitten forgot to set a selection while BuildOnlySelection is true"); + this.stopAtHeight = 0; + } else if (Baritone.settings().buildInLayers.value) { + OptionalInt minim = Stream.of(baritone.getSelectionManager().getSelections()).mapToInt(sel -> sel.min().y).min(); + OptionalInt maxim = Stream.of(baritone.getSelectionManager().getSelections()).mapToInt(sel -> sel.max().y).max(); + if (minim.isPresent() && maxim.isPresent()) { + int startAtHeight = Baritone.settings().layerOrder.value ? y + schematic.heightY() - maxim.getAsInt() : minim.getAsInt() - y; + this.stopAtHeight = (Baritone.settings().layerOrder.value ? y + schematic.heightY() - minim.getAsInt() : maxim.getAsInt() - y) + 1; + this.layer = Math.max(this.layer, startAtHeight / Baritone.settings().layerHeight.value); // startAtLayer or startAtHeight, whichever is highest + logDebug(String.format("Schematic starts at y=%s with height %s", y, schematic.heightY())); + logDebug(String.format("Selection starts at y=%s and ends at y=%s", minim.getAsInt(), maxim.getAsInt())); + logDebug(String.format("Considering relevant height %s - %s", startAtHeight, this.stopAtHeight)); + } + } + } + this.numRepeats = 0; this.observedCompleted = new LongOpenHashSet(); this.incorrectPositions = null; @@ -473,7 +495,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil } BuilderCalculationContext bcc = new BuilderCalculationContext(); if (!recalc(bcc)) { - if (Baritone.settings().buildInLayers.value && layer * Baritone.settings().layerHeight.value < realSchematic.heightY()) { + if (Baritone.settings().buildInLayers.value && layer * Baritone.settings().layerHeight.value < stopAtHeight) { logDirect("Starting layer " + layer); layer++; return onTick(calcFailed, isSafeToCancel, recursions + 1); @@ -652,7 +674,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil } // 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())) { + && !Baritone.settings().buildSkipBlocks.value.contains(schematic.desiredState(x, y, z, current, this.approxPlaceable).getBlock())) { // and we've never seen this position be correct // therefore mark as incorrect incorrectPositions.add(new BetterBlockPos(blockX, blockY, blockZ)); @@ -900,14 +922,21 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil TrapDoorBlock.OPEN, TrapDoorBlock.HALF ); - private boolean sameWithoutOrientation(BlockState first, BlockState second) { + private boolean sameBlockstate(BlockState first, BlockState second) { if (first.getBlock() != second.getBlock()) { return false; } + boolean ignoreDirection = Baritone.settings().buildIgnoreDirection.value; + List ignoredProps = Baritone.settings().buildIgnoreProperties.value; + if (!ignoreDirection && ignoredProps.isEmpty()) { + return first.equals(second); // early return if no properties are being ignored + } ImmutableMap, Comparable> map1 = first.getValues(); ImmutableMap, Comparable> map2 = second.getValues(); for (Property prop : map1.keySet()) { - if (map1.get(prop) != map2.get(prop) && !orientationProps.contains(prop)) { + if (map1.get(prop) != map2.get(prop) + && !(ignoreDirection && orientationProps.contains(prop)) + && !ignoredProps.contains(prop.getName())) { return false; } } @@ -939,7 +968,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil if (current.equals(desired)) { return true; } - return Baritone.settings().buildIgnoreDirection.value && sameWithoutOrientation(current, desired); + return sameBlockstate(current, desired); } public class BuilderCalculationContext extends CalculationContext { diff --git a/src/main/java/baritone/process/MineProcess.java b/src/main/java/baritone/process/MineProcess.java index b99369c96..c7bbec752 100644 --- a/src/main/java/baritone/process/MineProcess.java +++ b/src/main/java/baritone/process/MineProcess.java @@ -103,11 +103,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro return null; } } - if (!Baritone.settings().allowBreak.value) { - logDirect("Unable to mine when allowBreak is false!"); - cancel(); - return null; - } + updateLoucaSystem(); int mineGoalUpdateInterval = Baritone.settings().mineGoalUpdateInterval.value; List curr = new ArrayList<>(knownOreLocations); @@ -116,7 +112,10 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro Baritone.getExecutor().execute(() -> rescan(curr, context)); } if (Baritone.settings().legitMine.value) { - addNearby(); + if (!addNearby()) { + cancel(); + return null; + } } Optional shaft = curr.stream() .filter(pos -> pos.getX() == ctx.playerFeet().getX() && pos.getZ() == ctx.playerFeet().getZ()) @@ -178,6 +177,11 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro } private PathingCommand updateGoal() { + BlockOptionalMetaLookup filter = filterFilter(); + if (filter == null) { + return null; + } + boolean legit = Baritone.settings().legitMine.value; List locs = knownOreLocations; if (!locs.isEmpty()) { @@ -212,6 +216,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro public boolean isInGoal(int x, int y, int z) { return false; } + @Override public double heuristic() { return Double.NEGATIVE_INFINITY; @@ -222,6 +227,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro } private void rescan(List already, CalculationContext context) { + BlockOptionalMetaLookup filter = filterFilter(); if (filter == null) { return; } @@ -371,11 +377,18 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro return prune(ctx, locs, filter, max, blacklist, dropped); } - private void addNearby() { + private boolean addNearby() { List dropped = droppedItemsScan(); knownOreLocations.addAll(dropped); BlockPos playerFeet = ctx.playerFeet(); BlockStateInterface bsi = new BlockStateInterface(ctx); + + + BlockOptionalMetaLookup filter = filterFilter(); + if (filter == null) { + return false; + } + int searchDist = 10; double fakedBlockReachDistance = 20; // at least 10 * sqrt(3) with some extra space to account for positioning within the block for (int x = playerFeet.getX() - searchDist; x <= playerFeet.getX() + searchDist; x++) { @@ -393,6 +406,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro } } knownOreLocations = prune(new CalculationContext(baritone), knownOreLocations, filter, ORE_LOCATIONS_COUNT, blacklist, dropped); + return true; } private static List prune(CalculationContext ctx, List locs2, BlockOptionalMetaLookup filter, int max, List blacklist, List dropped) { @@ -468,10 +482,8 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro @Override public void mine(int quantity, BlockOptionalMetaLookup filter) { this.filter = filter; - if (filter != null && !Baritone.settings().allowBreak.value) { - logDirect("Unable to mine when allowBreak is false!"); - this.mine(quantity, (BlockOptionalMetaLookup) null); - return; + if (this.filterFilter() == null) { + this.filter = null; } this.desiredQuantity = quantity; this.knownOreLocations = new ArrayList<>(); @@ -483,4 +495,22 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro rescan(new ArrayList<>(), new CalculationContext(baritone)); } } + + private BlockOptionalMetaLookup filterFilter() { + if (this.filter == null) { + return null; + } + if (!Baritone.settings().allowBreak.value) { + BlockOptionalMetaLookup f = new BlockOptionalMetaLookup(this.filter.blocks() + .stream() + .filter(e -> Baritone.settings().allowBreakAnyway.value.contains(e.getBlock())) + .toArray(BlockOptionalMeta[]::new)); + if (f.blocks().isEmpty()) { + logDirect("Unable to mine when allowBreak is false and target block is not in allowBreakAnyway!"); + return null; + } + return f; + } + return filter; + } } diff --git a/src/main/java/baritone/utils/PathRenderer.java b/src/main/java/baritone/utils/PathRenderer.java index db7d11b34..5f50962e7 100644 --- a/src/main/java/baritone/utils/PathRenderer.java +++ b/src/main/java/baritone/utils/PathRenderer.java @@ -229,8 +229,7 @@ public final class PathRenderer implements IRenderer, Helper { if (!settings.renderGoalAnimated.value) { // y = 1 causes rendering issues when the player is at the same y as the top of a block for some reason y = 0.999F; - } - else { + } else { y = Mth.cos((float) (((float) ((System.nanoTime() / 100000L) % 20000L)) / 20000F * Math.PI * 2)); } if (goal instanceof IGoalRenderPos) { diff --git a/src/main/java/baritone/utils/ToolSet.java b/src/main/java/baritone/utils/ToolSet.java index fa2aee628..38b1fafdd 100644 --- a/src/main/java/baritone/utils/ToolSet.java +++ b/src/main/java/baritone/utils/ToolSet.java @@ -128,7 +128,7 @@ public class ToolSet { if (!Baritone.settings().useSwordToMine.value && itemStack.getItem() instanceof SwordItem) { continue; } - + if (Baritone.settings().itemSaver.value && (itemStack.getDamageValue() + Baritone.settings().itemSaverThreshold.value) >= itemStack.getMaxDamage() && itemStack.getMaxDamage() > 1) { continue; } diff --git a/src/main/java/baritone/utils/accessor/INBTTagLongArray.java b/src/main/java/baritone/utils/accessor/INBTTagLongArray.java deleted file mode 100644 index fe4f0bd87..000000000 --- a/src/main/java/baritone/utils/accessor/INBTTagLongArray.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * This file is part of Baritone. - * - * Baritone is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Baritone is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Baritone. If not, see . - */ - -package baritone.utils.accessor; - -/** - * @author rycbar - * @since 26.09.2022 - */ -public interface INBTTagLongArray { - - long[] getLongArray(); -} \ No newline at end of file diff --git a/src/main/java/baritone/utils/schematic/SelectionSchematic.java b/src/main/java/baritone/utils/schematic/SelectionSchematic.java index 5a461be4b..bc62e19f0 100644 --- a/src/main/java/baritone/utils/schematic/SelectionSchematic.java +++ b/src/main/java/baritone/utils/schematic/SelectionSchematic.java @@ -33,10 +33,10 @@ public class SelectionSchematic extends MaskSchematic { public SelectionSchematic(ISchematic schematic, Vec3i origin, ISelection[] selections) { super(schematic); this.selections = Stream.of(selections).map( - sel -> sel - .shift(Direction.WEST, origin.getX()) - .shift(Direction.DOWN, origin.getY()) - .shift(Direction.NORTH, origin.getZ())) + sel -> sel + .shift(Direction.WEST, origin.getX()) + .shift(Direction.DOWN, origin.getY()) + .shift(Direction.NORTH, origin.getZ())) .toArray(ISelection[]::new); } @@ -44,7 +44,7 @@ public class SelectionSchematic extends MaskSchematic { protected boolean partOfMask(int x, int y, int z, BlockState currentState) { for (ISelection selection : selections) { if (x >= selection.min().x && y >= selection.min().y && z >= selection.min().z - && x <= selection.max().x && y <= selection.max().y && z <= selection.max().z) { + && x <= selection.max().x && y <= selection.max().y && z <= selection.max().z) { return true; } } 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 24b0bc13e..9fd672d62 100644 --- a/src/main/java/baritone/utils/schematic/format/defaults/LitematicaSchematic.java +++ b/src/main/java/baritone/utils/schematic/format/defaults/LitematicaSchematic.java @@ -17,7 +17,6 @@ package baritone.utils.schematic.format.defaults; -import baritone.utils.accessor.ILongArrayNBT; import baritone.utils.schematic.StaticSchematic; import net.minecraft.core.Registry; import net.minecraft.core.Vec3i; @@ -137,7 +136,7 @@ public final class LitematicaSchematic extends StaticSchematic { * @return amount of bits used to encode a block. */ private static int getBitsPerBlock(int amountOfBlockTypes) { - return (int) Math.floor((Math.log(amountOfBlockTypes)) / Math.log(2)) + 1; + return (int) Math.max(2, Math.ceil(Math.log(amountOfBlockTypes) / Math.log(2))); } /** @@ -157,7 +156,7 @@ public final class LitematicaSchematic extends StaticSchematic { * @return array of Long values. */ private static long[] getBlockStates(CompoundTag nbt, String subReg) { - return ((ILongArrayNBT) nbt.getCompound("Regions").getCompound(subReg).get("BlockStates")).getLongArray(); + return nbt.getCompound("Regions").getCompound(subReg).getLongArray("BlockStates"); } /**