diff --git a/README.md b/README.md index c09e3c1e6..08aac2b99 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ Here are some links to help to get started: - [Installation & setup](SETUP.md) -- [API Javadocs](https://baritone.leijurv.com/) +- [API Javadocs](https://baritone.leijurv.com) - [Settings](https://baritone.leijurv.com/baritone/api/Settings.html#field.detail) diff --git a/USAGE.md b/USAGE.md index 224603786..652c093ea 100644 --- a/USAGE.md +++ b/USAGE.md @@ -34,15 +34,18 @@ Some common examples: - `cancel` or `stop` to stop everything - `goto portal` or `goto ender_chest` or `goto block_type` to go to a block. (in Impact, `.goto` is an alias for `.b goto` for the most part) - `mine diamond_ore` to mine diamond ore (turn on the setting `legitMine` to only mine ores that it can actually see. It will explore randomly around y=11 until it finds them.) -- `click` to click your destination on the screen. left click to path into it, right click to path on top of it. left click and drag to clear an area. +- `click` to click your destination on the screen. Right click path to on top of the block, left click to path into it (either at foot level or eye level), and left click and drag to clear all blocks from an area. - `follow playerName` to follow a player. `follow` to follow the entity you're looking at (only works if it hitting range). `followplayers` to follow any players in range (combine with Kill Aura for a fun time). - `save waypointName` to save a waypoint. `goto waypointName` to go to it. +- `build` to build a schematic. `build blah` will load `schematics/blah.schematic` and build it with the origin being your player feet. `build blah x y z` to set the origin. Any of those can be relative to your player (`~ 69 ~-420` would build at x=player x, y=69, z=player z-420). +- `tunnel` to dig just straight ahead and make a tunnel +- `farm` to automatically harvest, replant, or bone meal crops - `axis` to go to an axis or diagonal axis at y=120 (`axisHeight` is a configurable setting, defaults to 120). +- `explore x z` to explore the world from the origin of x,z. Leave out x and z to default to player feet. This will continually path towards the closest chunk to the origin that it's never seen before. `explorefilter filter.json` with optional invert can be used to load in a list of chunks to load. - `invert` to invert the current goal and path. This gets as far away from it as possible, instead of as close as possible. For example, do `goal` then `invert` to run as far as possible from where you're standing at the start. -- `render` to rerender the world in case `renderCachedChunks` is being glitchy - `version` to get the version of Baritone you're running - `damn` daniel -- `build` to build a schematic. `build blah` will load `schematics/blah.schematic` and build it with the origin being your player feet. `build blah x y z` to set the origin. Any of those can be relative to your player (`~ 69 ~-420` would build at x=player x, y=69, z=player z-420). + For the rest of the commands, you can take a look at the code [here](https://github.com/cabaletta/baritone/blob/master/src/main/java/baritone/utils/ExampleBaritoneControl.java). @@ -54,18 +57,23 @@ There are about a hundred settings, but here are some fun / interesting / import - `allowPlace` - `allowParkour` - `allowParkourPlace` +- `blockPlacementPenalty` - `renderCachedChunks` (and `cachedChunksOpacity`) <-- very fun but you need a beefy computer -- `avoidance` +- `avoidance` (avoidance of mobs / mob spawners) - `legitMine` - `followRadius` +- `backfill` (fill in tunnels behind you) +- `buildInLayers` +- `buildRepeatDistance` and `buildRepeatDirection` +- `worldExploringChunkOffset` +- `acceptableThrowawayItems` +- `blocksToAvoidBreaking` + # Troubleshooting / common issues -## Baritone highlights a block in green but gets completely stuck? Also I'm using Baritone with Future? -Baritone is trying to right click to place a block there, but it can't since there's a conflicting mixin. Baritone can't force click right click when Future is also installed. Left click **does work** on recent Baritone even with Future, however. For now, turn off `allowPlace` and Baritone will only search for paths that don't require placing blocks to complete. `allowBreak` can remain on. - ## Why doesn't Baritone respond to any of my chat commands? This could be one of many things. diff --git a/scripts/proguard.pro b/scripts/proguard.pro index d570cd449..5e2f8b03c 100644 --- a/scripts/proguard.pro +++ b/scripts/proguard.pro @@ -23,6 +23,8 @@ -keep class baritone.BaritoneProvider -keep class baritone.api.IBaritoneProvider +-keep class baritone.api.utils.MyChunkPos { *; } # even in standalone we need to keep this for gson reflect + # setting names are reflected from field names, so keep field names -keepclassmembers class baritone.api.Settings { public ; diff --git a/src/api/java/baritone/api/IBaritone.java b/src/api/java/baritone/api/IBaritone.java index a12b206d2..a356922cc 100644 --- a/src/api/java/baritone/api/IBaritone.java +++ b/src/api/java/baritone/api/IBaritone.java @@ -71,6 +71,18 @@ public interface IBaritone { */ IBuilderProcess getBuilderProcess(); + /** + * @return The {@link IExploreProcess} instance + * @see IExploreProcess + */ + IExploreProcess getExploreProcess(); + + /** + * @return The {@link IFarmProcess} instance + * @see IFarmProcess + */ + IFarmProcess getFarmProcess(); + /** * @return The {@link ICustomGoalProcess} instance * @see ICustomGoalProcess @@ -115,4 +127,6 @@ public interface IBaritone { * @see IEventBus */ IEventBus getGameEventHandler(); + + void openClick(); } diff --git a/src/api/java/baritone/api/Settings.java b/src/api/java/baritone/api/Settings.java index 080baa7ec..4e0dd3a1d 100644 --- a/src/api/java/baritone/api/Settings.java +++ b/src/api/java/baritone/api/Settings.java @@ -18,6 +18,8 @@ package baritone.api; import baritone.api.utils.SettingsUtil; +import baritone.api.utils.TypeUtils; +import net.minecraft.block.Block; import net.minecraft.client.Minecraft; import net.minecraft.init.Blocks; import net.minecraft.item.Item; @@ -26,6 +28,8 @@ import net.minecraft.util.text.ITextComponent; import java.awt.*; import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; import java.util.*; import java.util.List; import java.util.function.Consumer; @@ -80,7 +84,7 @@ public final class Settings { /** * Walking on water uses up hunger really quick, so penalize it */ - public final Setting walkOnWaterOnePenalty = new Setting<>(5D); + public final Setting walkOnWaterOnePenalty = new Setting<>(3D); /** * Allow Baritone to fall arbitrary distances and place a water bucket beneath it. @@ -142,9 +146,34 @@ public final class Settings { public final Setting> acceptableThrowawayItems = new Setting<>(new ArrayList<>(Arrays.asList( Blocks.DIRT.asItem(), Blocks.COBBLESTONE.asItem(), - Blocks.NETHERRACK.asItem() + Blocks.NETHERRACK.asItem(), + Blocks.STONE.asItem() ))); + /** + * Blocks that Baritone will attempt to avoid (Used in avoidance) + */ + public final Setting> blocksToAvoid = new Setting<>(new ArrayList<>( + // Leave Empty by Default + )); + + /** + * Blocks that Baritone is not allowed to break + */ + public final Setting> blocksToAvoidBreaking = new Setting<>(new ArrayList<>(Arrays.asList( // TODO can this be a HashSet or ImmutableSet? + Blocks.CRAFTING_TABLE, + Blocks.FURNACE, + Blocks.CHEST, + Blocks.TRAPPED_CHEST + ))); + + /** + * If this setting is true, Baritone will never break a block that is adjacent to an unsupported falling block. + *

+ * I.E. it will never trigger cascading sand / gravel falls + */ + public final Setting avoidUpdatingFallingBlocks = new Setting<>(true); + /** * Enables some more advanced vine features. They're honestly just gimmicks and won't ever be needed in real * pathing scenarios. And they can cause Baritone to get trapped indefinitely in a strange scenario. @@ -185,6 +214,11 @@ public final class Settings { */ public final Setting sprintAscends = new Setting<>(true); + /** + * When breaking blocks for a movement, wait until all falling blocks have settled before continuing + */ + public final Setting pauseMiningForFallingBlocks = new Setting<>(true); + /** * How many ticks between right clicks are allowed. Default in game is 4 */ @@ -415,6 +449,11 @@ public final class Settings { */ public final Setting containerMemory = new Setting<>(false); + /** + * Fill in blocks behind you + */ + public final Setting backfill = new Setting<>(false); + /** * Print all the debug messages to chat */ @@ -543,6 +582,16 @@ public final class Settings { */ public final Setting walkWhileBreaking = new Setting<>(true); + /** + * When a new segment is calculated that doesn't overlap with the current one, but simply begins where the current segment ends, + * splice it on and make a longer combined path. If this setting is off, any planned segment will not be spliced and will instead + * be the "next path" in PathingBehavior, and will only start after this one ends. Turning this off hurts planning ahead, + * because the next segment will exist even if it's very short. + * + * @see #planningTickLookahead + */ + public final Setting splicePath = new Setting<>(true); + /** * If we are more than 300 movements into the current path, discard the oldest segments, as they are no longer useful */ @@ -569,6 +618,37 @@ public final class Settings { */ public final Setting exploreForBlocks = new Setting<>(true); + /** + * While exploring the world, offset the closest unloaded chunk by this much in both axes. + *

+ * This can result in more efficient loading, if you set this to the render distance. + */ + public final Setting worldExploringChunkOffset = new Setting<>(0); + + /** + * Take the 10 closest chunks, even if they aren't strictly tied for distance metric from origin. + */ + public final Setting exploreChunkSetMinimumSize = new Setting<>(10); + + /** + * Attempt to maintain Y coordinate while exploring + *

+ * -1 to disable + */ + public final Setting exploreMaintainY = new Setting<>(64); + + /** + * Replant nether wart + */ + public final Setting replantNetherWart = new Setting<>(false); + + /** + * When the cache scan gives less blocks than the maximum threshold (but still above zero), scan the main world too. + *

+ * Only if you have a beefy CPU and automatically mine blocks that are in cache + */ + public final Setting extendCacheOnThreshold = new Setting<>(false); + /** * Don't consider the next layer in builder until the current one is done */ @@ -580,10 +660,24 @@ public final class Settings { public final Setting buildRepeatDistance = new Setting<>(0); /** - * What direction te repeat the build in + * What direction to repeat the build in */ public final Setting buildRepeatDirection = new Setting<>(EnumFacing.NORTH); + /** + * Allow standing above a block while mining it, in BuilderProcess + *

+ * Experimental + */ + public final Setting breakFromAbove = new Setting<>(false); + + /** + * As well as breaking from above, set a goal to up and to the side of all blocks to break. + *

+ * Never turn this on without also turning on breakFromAbove. + */ + public final Setting goalBreakFromAbove = new Setting<>(false); + /** * While mining, should it also consider dropped items of the correct type as a pathing destination (as well as ore blocks)? */ @@ -670,11 +764,10 @@ public final class Settings { public final Setting followRadius = new Setting<>(3); /** - * true = exploration uses pythagorean distance to choose closest uncached chunk - *

- * false = exploration uses manhattan / taxicab distance to choose + * Turn this on if your exploration filter is enormous, you don't want it to check if it's done, + * and you are just fine with it just hanging on completion */ - public final Setting exploreUsePythagorean = new Setting<>(false); + public final Setting disableCompletionCheck = new Setting<>(false); /** * Cached chunks (regardless of if they're in RAM or saved to disk) expire and are deleted after this number of seconds @@ -756,11 +849,12 @@ public final class Settings { */ public final List> allSettings; + public final Map, Type> settingTypes; + public final class Setting { public T value; public final T defaultValue; private String name; - private final Class klass; @SuppressWarnings("unchecked") private Setting(T value) { @@ -769,7 +863,6 @@ public final class Settings { } this.value = value; this.defaultValue = value; - this.klass = (Class) value.getClass(); } /** @@ -787,7 +880,8 @@ public final class Settings { } public Class getValueClass() { - return klass; + // noinspection unchecked + return (Class) TypeUtils.resolveBaseClass(getType()); } @Override @@ -801,14 +895,21 @@ public final class Settings { public void reset() { value = defaultValue; } + + public final Type getType() { + return settingTypes.get(this); + } } // here be dragons Settings() { Field[] temp = getClass().getFields(); - HashMap> tmpByName = new HashMap<>(); + + Map> tmpByName = new HashMap<>(); List> tmpAll = new ArrayList<>(); + Map, Type> tmpSettingTypes = new HashMap<>(); + try { for (Field field : temp) { if (field.getType().equals(Setting.class)) { @@ -821,6 +922,7 @@ public final class Settings { } tmpByName.put(name, setting); tmpAll.add(setting); + tmpSettingTypes.put(setting, ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]); } } } catch (IllegalAccessException e) { @@ -828,6 +930,7 @@ public final class Settings { } byLowerName = Collections.unmodifiableMap(tmpByName); allSettings = Collections.unmodifiableList(tmpAll); + settingTypes = Collections.unmodifiableMap(tmpSettingTypes); } @SuppressWarnings("unchecked") diff --git a/src/api/java/baritone/api/behavior/IBehavior.java b/src/api/java/baritone/api/behavior/IBehavior.java index fbef52580..811563b93 100644 --- a/src/api/java/baritone/api/behavior/IBehavior.java +++ b/src/api/java/baritone/api/behavior/IBehavior.java @@ -23,9 +23,8 @@ import baritone.api.event.listener.IGameEventListener; /** * A behavior is simply a type that is able to listen to events. * - * @see IGameEventListener - * * @author Brady + * @see IGameEventListener * @since 9/23/2018 */ public interface IBehavior extends AbstractGameEventListener {} diff --git a/src/api/java/baritone/api/behavior/IPathingBehavior.java b/src/api/java/baritone/api/behavior/IPathingBehavior.java index 64be71d50..157774489 100644 --- a/src/api/java/baritone/api/behavior/IPathingBehavior.java +++ b/src/api/java/baritone/api/behavior/IPathingBehavior.java @@ -80,6 +80,13 @@ public interface IPathingBehavior extends IBehavior { */ boolean cancelEverything(); + /** + * PLEASE never call this + *

+ * If cancelEverything was like "kill" this is "sudo kill -9". Or shutting off your computer. + */ + void forceCancel(); + /** * Returns the current path, from the current path executor, if there is one. * diff --git a/src/api/java/baritone/api/cache/ICachedWorld.java b/src/api/java/baritone/api/cache/ICachedWorld.java index e681ce51c..837ae076c 100644 --- a/src/api/java/baritone/api/cache/ICachedWorld.java +++ b/src/api/java/baritone/api/cache/ICachedWorld.java @@ -81,4 +81,6 @@ public interface ICachedWorld { * in a new thread by default. */ void save(); + + } diff --git a/src/main/java/baritone/cache/Waypoint.java b/src/api/java/baritone/api/cache/Waypoint.java similarity index 94% rename from src/main/java/baritone/cache/Waypoint.java rename to src/api/java/baritone/api/cache/Waypoint.java index 19e574f9b..2b9a7232b 100644 --- a/src/main/java/baritone/cache/Waypoint.java +++ b/src/api/java/baritone/api/cache/Waypoint.java @@ -15,9 +15,8 @@ * along with Baritone. If not, see . */ -package baritone.cache; +package baritone.api.cache; -import baritone.api.cache.IWaypoint; import net.minecraft.util.math.BlockPos; import java.util.Date; @@ -47,7 +46,7 @@ public class Waypoint implements IWaypoint { * @param location The waypoint location * @param creationTimestamp When the waypoint was created */ - Waypoint(String name, Tag tag, BlockPos location, long creationTimestamp) { + public Waypoint(String name, Tag tag, BlockPos location, long creationTimestamp) { this.name = name; this.tag = tag; this.location = location; diff --git a/src/api/java/baritone/api/pathing/goals/GoalStrictDirection.java b/src/api/java/baritone/api/pathing/goals/GoalStrictDirection.java index 749bed626..24ae385ac 100644 --- a/src/api/java/baritone/api/pathing/goals/GoalStrictDirection.java +++ b/src/api/java/baritone/api/pathing/goals/GoalStrictDirection.java @@ -17,7 +17,6 @@ package baritone.api.pathing.goals; -import baritone.api.BaritoneAPI; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; diff --git a/src/api/java/baritone/api/pathing/goals/GoalTwoBlocks.java b/src/api/java/baritone/api/pathing/goals/GoalTwoBlocks.java index b1dc07a1d..f1026ab50 100644 --- a/src/api/java/baritone/api/pathing/goals/GoalTwoBlocks.java +++ b/src/api/java/baritone/api/pathing/goals/GoalTwoBlocks.java @@ -31,17 +31,17 @@ public class GoalTwoBlocks implements Goal, IGoalRenderPos { /** * The X block position of this goal */ - private final int x; + protected final int x; /** * The Y block position of this goal */ - private final int y; + protected final int y; /** * The Z block position of this goal */ - private final int z; + protected final int z; public GoalTwoBlocks(BlockPos pos) { this(pos.getX(), pos.getY(), pos.getZ()); diff --git a/src/api/java/baritone/api/process/IBuilderProcess.java b/src/api/java/baritone/api/process/IBuilderProcess.java index 694c8752b..8b15fba1c 100644 --- a/src/api/java/baritone/api/process/IBuilderProcess.java +++ b/src/api/java/baritone/api/process/IBuilderProcess.java @@ -18,6 +18,8 @@ package baritone.api.process; import baritone.api.utils.ISchematic; +import net.minecraft.client.Minecraft; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3i; import java.io.File; @@ -46,4 +48,15 @@ public interface IBuilderProcess extends IBaritoneProcess { * @return Whether or not the schematic was able to load from file */ boolean build(String name, File schematic, Vec3i origin); + + default boolean build(String schematicFile, BlockPos origin) { + File file = new File(new File(Minecraft.getInstance().gameDir, "schematics"), schematicFile); + return build(schematicFile, file, origin); + } + + void pause(); + + void resume(); + + void clearArea(BlockPos corner1, BlockPos corner2); } diff --git a/src/api/java/baritone/api/process/IExploreProcess.java b/src/api/java/baritone/api/process/IExploreProcess.java new file mode 100644 index 000000000..811a509f0 --- /dev/null +++ b/src/api/java/baritone/api/process/IExploreProcess.java @@ -0,0 +1,26 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package baritone.api.process; + +import java.nio.file.Path; + +public interface IExploreProcess extends IBaritoneProcess { + void explore(int centerX, int centerZ); + + void applyJsonFilter(Path path, boolean invert) throws Exception; +} diff --git a/src/api/java/baritone/api/process/IFarmProcess.java b/src/api/java/baritone/api/process/IFarmProcess.java new file mode 100644 index 000000000..c9234a24a --- /dev/null +++ b/src/api/java/baritone/api/process/IFarmProcess.java @@ -0,0 +1,22 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package baritone.api.process; + +public interface IFarmProcess extends IBaritoneProcess { + void farm(); +} diff --git a/src/api/java/baritone/api/process/IGetToBlockProcess.java b/src/api/java/baritone/api/process/IGetToBlockProcess.java index ff3dc9b53..a5a35577e 100644 --- a/src/api/java/baritone/api/process/IGetToBlockProcess.java +++ b/src/api/java/baritone/api/process/IGetToBlockProcess.java @@ -25,4 +25,6 @@ import net.minecraft.block.Block; public interface IGetToBlockProcess extends IBaritoneProcess { void getToBlock(Block block); + + boolean blacklistClosest(); } diff --git a/src/api/java/baritone/api/process/PathingCommandType.java b/src/api/java/baritone/api/process/PathingCommandType.java index da64748aa..af25591af 100644 --- a/src/api/java/baritone/api/process/PathingCommandType.java +++ b/src/api/java/baritone/api/process/PathingCommandType.java @@ -51,5 +51,10 @@ public enum PathingCommandType { *

* Cancel the current path if the goals are not equal */ - FORCE_REVALIDATE_GOAL_AND_PATH + FORCE_REVALIDATE_GOAL_AND_PATH, + + /** + * Go and ask the next process what to do + */ + DEFER } diff --git a/src/api/java/baritone/api/utils/BlockUtils.java b/src/api/java/baritone/api/utils/BlockUtils.java new file mode 100644 index 000000000..fd376c9a8 --- /dev/null +++ b/src/api/java/baritone/api/utils/BlockUtils.java @@ -0,0 +1,67 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package baritone.api.utils; + +import net.minecraft.block.Block; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.registry.IRegistry; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +public class BlockUtils { + private static transient Map resourceCache = new HashMap<>(); + + public static String blockToString(Block block) { + ResourceLocation loc = IRegistry.BLOCK.getKey(block); + String name = loc.getPath(); // normally, only write the part after the minecraft: + if (!loc.getNamespace().equals("minecraft")) { + // Baritone is running on top of forge with mods installed, perhaps? + name = loc.toString(); // include the namespace with the colon + } + return name; + } + + public static Block stringToBlockRequired(String name) { + if (name.equals("lit_redstone_ore")) { // workaround for Impact 4.6 only + return stringToBlockRequired("redstone_ore"); + } + Block block = stringToBlockNullable(name); + Objects.requireNonNull(block); + return block; + } + + public static Block stringToBlockNullable(String name) { + // do NOT just replace this with a computeWithAbsent, it isn't thread safe + Block block = resourceCache.get(name); // map is never mutated in place so this is safe + if (block != null) { + return block; + } + if (resourceCache.containsKey(name)) { + return null; // cached as null + } + block = IRegistry.BLOCK.get(ResourceLocation.tryCreate(name.contains(":") ? name : "minecraft:" + name)); + Map copy = new HashMap<>(resourceCache); // read only copy is safe, wont throw concurrentmodification + copy.put(name, block); + resourceCache = copy; + return block; + } + + private BlockUtils() {} +} diff --git a/src/main/java/baritone/utils/ExampleBaritoneControl.java b/src/api/java/baritone/api/utils/ExampleBaritoneControl.java similarity index 82% rename from src/main/java/baritone/utils/ExampleBaritoneControl.java rename to src/api/java/baritone/api/utils/ExampleBaritoneControl.java index 6908b3cb5..47dcde32d 100644 --- a/src/main/java/baritone/utils/ExampleBaritoneControl.java +++ b/src/api/java/baritone/api/utils/ExampleBaritoneControl.java @@ -15,27 +15,21 @@ * along with Baritone. If not, see . */ -package baritone.utils; +package baritone.api.utils; -import baritone.Baritone; +import baritone.api.BaritoneAPI; +import baritone.api.IBaritone; import baritone.api.Settings; +import baritone.api.behavior.IPathingBehavior; import baritone.api.cache.IRememberedInventory; import baritone.api.cache.IWaypoint; +import baritone.api.cache.Waypoint; import baritone.api.event.events.ChatEvent; +import baritone.api.event.listener.AbstractGameEventListener; import baritone.api.pathing.goals.*; -import baritone.api.pathing.movement.ActionCosts; import baritone.api.process.IBaritoneProcess; -import baritone.api.utils.BetterBlockPos; -import baritone.api.utils.SettingsUtil; -import baritone.behavior.Behavior; -import baritone.behavior.PathingBehavior; -import baritone.cache.ChunkPacker; -import baritone.cache.Waypoint; -import baritone.pathing.movement.CalculationContext; -import baritone.pathing.movement.Movement; -import baritone.pathing.movement.Moves; -import baritone.process.CustomGoalProcess; -import baritone.utils.pathing.SegmentedCalculator; +import baritone.api.process.ICustomGoalProcess; +import baritone.api.process.IGetToBlockProcess; import net.minecraft.block.Block; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ChunkProviderClient; @@ -45,11 +39,10 @@ import net.minecraft.item.ItemStack; import net.minecraft.util.math.BlockPos; import net.minecraft.world.chunk.Chunk; +import java.nio.file.Path; import java.util.*; -import java.util.stream.Collectors; -import java.util.stream.Stream; -public class ExampleBaritoneControl extends Behavior implements Helper { +public class ExampleBaritoneControl implements Helper, AbstractGameEventListener { private static final String HELP_MSG = "baritone - Output settings into chat\n" + @@ -83,21 +76,26 @@ public class ExampleBaritoneControl extends Behavior implements Helper { private static final String COMMAND_PREFIX = "#"; - public ExampleBaritoneControl(Baritone baritone) { - super(baritone); + public final IBaritone baritone; + public final IPlayerContext ctx; + + public ExampleBaritoneControl(IBaritone baritone) { + this.baritone = baritone; + this.ctx = baritone.getPlayerContext(); + baritone.getGameEventHandler().registerEventListener(this); } @Override public void onSendChatMessage(ChatEvent event) { String msg = event.getMessage(); - if (Baritone.settings().prefixControl.value && msg.startsWith(COMMAND_PREFIX)) { + if (BaritoneAPI.getSettings().prefixControl.value && msg.startsWith(COMMAND_PREFIX)) { if (!runCommand(msg.substring(COMMAND_PREFIX.length()))) { logDirect("Invalid command"); } event.cancel(); // always cancel if using prefixControl return; } - if (!Baritone.settings().chatControl.value && !Baritone.settings().removePrefix.value) { + if (!BaritoneAPI.getSettings().chatControl.value && !BaritoneAPI.getSettings().removePrefix.value) { return; } if (runCommand(msg)) { @@ -107,20 +105,20 @@ public class ExampleBaritoneControl extends Behavior implements Helper { public boolean runCommand(String msg0) { // you may think this can be private, but impcat calls it from .b =) String msg = msg0.toLowerCase(Locale.US).trim(); // don't reassign the argument LOL - PathingBehavior pathingBehavior = baritone.getPathingBehavior(); - CustomGoalProcess customGoalProcess = baritone.getCustomGoalProcess(); - List> toggleable = Baritone.settings().getAllValuesByType(Boolean.class); + IPathingBehavior pathingBehavior = baritone.getPathingBehavior(); + ICustomGoalProcess customGoalProcess = baritone.getCustomGoalProcess(); + List> toggleable = BaritoneAPI.getSettings().getAllValuesByType(Boolean.class); for (Settings.Setting setting : toggleable) { if (msg.equalsIgnoreCase(setting.getName())) { setting.value ^= true; logDirect("Toggled " + setting.getName() + " to " + setting.value); - SettingsUtil.save(Baritone.settings()); + SettingsUtil.save(BaritoneAPI.getSettings()); return true; } } if (msg.equals("baritone") || msg.equals("modifiedsettings") || msg.startsWith("settings m") || msg.equals("modified")) { logDirect("All settings that have been modified from their default values:"); - for (Settings.Setting setting : SettingsUtil.modifiedSettings(Baritone.settings())) { + for (Settings.Setting setting : SettingsUtil.modifiedSettings(BaritoneAPI.getSettings())) { logDirect(setting.toString()); } return true; @@ -130,15 +128,15 @@ public class ExampleBaritoneControl extends Behavior implements Helper { try { int page = Integer.parseInt(rest.trim()); int min = page * 10; - int max = Math.min(Baritone.settings().allSettings.size(), (page + 1) * 10); + int max = Math.min(BaritoneAPI.getSettings().allSettings.size(), (page + 1) * 10); logDirect("Settings " + min + " to " + (max - 1) + ":"); for (int i = min; i < max; i++) { - logDirect(Baritone.settings().allSettings.get(i).toString()); + logDirect(BaritoneAPI.getSettings().allSettings.get(i).toString()); } } catch (Exception ex) { // NumberFormatException | ArrayIndexOutOfBoundsException and probably some others I'm forgetting lol ex.printStackTrace(); logDirect("All settings:"); - for (Settings.Setting setting : Baritone.settings().allSettings) { + for (Settings.Setting setting : BaritoneAPI.getSettings().allSettings) { logDirect(setting.toString()); } logDirect("To get one page of ten settings at a time, do settings "); @@ -154,26 +152,26 @@ public class ExampleBaritoneControl extends Behavior implements Helper { if (msg.contains(" ")) { String settingName = msg.substring(0, msg.indexOf(' ')); String settingValue = msg.substring(msg.indexOf(' ') + 1); - Settings.Setting setting = Baritone.settings().byLowerName.get(settingName); + Settings.Setting setting = BaritoneAPI.getSettings().byLowerName.get(settingName); if (setting != null) { if (settingValue.equals("reset")) { logDirect("Resetting setting " + settingName + " to default value."); setting.reset(); } else { try { - SettingsUtil.parseAndApply(Baritone.settings(), settingName, settingValue); + SettingsUtil.parseAndApply(BaritoneAPI.getSettings(), settingName, settingValue); } catch (Exception ex) { logDirect("Unable to parse setting"); return true; } } - SettingsUtil.save(Baritone.settings()); + SettingsUtil.save(BaritoneAPI.getSettings()); logDirect(setting.toString()); return true; } } - if (Baritone.settings().byLowerName.containsKey(msg)) { - Settings.Setting setting = Baritone.settings().byLowerName.get(msg); + if (BaritoneAPI.getSettings().byLowerName.containsKey(msg)) { + Settings.Setting setting = BaritoneAPI.getSettings().byLowerName.get(msg); logDirect(setting.toString()); return true; } @@ -209,7 +207,7 @@ public class ExampleBaritoneControl extends Behavior implements Helper { } return true; } - if (msg.equals("fullpath")) { + /*if (msg.equals("fullpath")) { if (pathingBehavior.getGoal() == null) { logDirect("No goal."); } else { @@ -225,7 +223,7 @@ public class ExampleBaritoneControl extends Behavior implements Helper { }); } return true; - } + }*/ if (msg.equals("proc")) { Optional proc = baritone.getPathingControlManager().mostRecentInControl(); if (!proc.isPresent()) { @@ -283,7 +281,7 @@ public class ExampleBaritoneControl extends Behavior implements Helper { return true; } if (msg.equals("come")) { - customGoalProcess.setGoalAndPath(new GoalBlock(new BlockPos(mc.getRenderViewEntity()))); + customGoalProcess.setGoalAndPath(new GoalBlock(new BlockPos(Helper.mc.getRenderViewEntity()))); logDirect("Coming"); return true; } @@ -358,11 +356,16 @@ public class ExampleBaritoneControl extends Behavior implements Helper { logDirect("resumed"); return true; } + if (msg.equals("pause")) { + baritone.getBuilderProcess().pause(); + logDirect("paused"); + return true; + } if (msg.equals("reset")) { - for (Settings.Setting setting : Baritone.settings().allSettings) { + for (Settings.Setting setting : BaritoneAPI.getSettings().allSettings) { setting.reset(); } - SettingsUtil.save(Baritone.settings()); + SettingsUtil.save(BaritoneAPI.getSettings()); logDirect("Baritone settings reset"); return true; } @@ -377,7 +380,13 @@ public class ExampleBaritoneControl extends Behavior implements Helper { logDirect("okay"); return true; } - if (msg.equals("echest")) { + if (msg.equals("farm")) { + baritone.getFarmProcess().farm(); + logDirect("farming"); + return true; + } + // this literally doesn't work, memory is disabled lol + /*if (msg.equals("echest")) { Optional> contents = baritone.getMemoryBehavior().echest(); if (contents.isPresent()) { logDirect("echest contents:"); @@ -386,18 +395,8 @@ public class ExampleBaritoneControl extends Behavior implements Helper { logDirect("echest contents unknown"); } return true; - } + }*/ if (msg.equals("chests")) { - System.out.println(baritone.getWorldProvider()); - System.out.println(baritone.getWorldProvider().getCurrentWorld()); - - System.out.println(baritone.getWorldProvider().getCurrentWorld().getContainerMemory()); - - System.out.println(baritone.getWorldProvider().getCurrentWorld().getContainerMemory().getRememberedInventories()); - - System.out.println(baritone.getWorldProvider().getCurrentWorld().getContainerMemory().getRememberedInventories().entrySet()); - - System.out.println(baritone.getWorldProvider().getCurrentWorld().getContainerMemory().getRememberedInventories().entrySet()); for (Map.Entry entry : baritone.getWorldProvider().getCurrentWorld().getContainerMemory().getRememberedInventories().entrySet()) { logDirect(entry.getKey() + ""); log(entry.getValue().getContents()); @@ -431,6 +430,29 @@ public class ExampleBaritoneControl extends Behavior implements Helper { logDirect("Following " + toFollow.get()); return true; } + if (msg.startsWith("explorefilter")) { + // explorefilter blah.json + // means that entries in blah.json are already explored + // explorefilter blah.json invert + // means that entries in blah.json are NOT already explored + String path = msg.substring("explorefilter".length()).trim(); + String[] parts = path.split(" "); + Path path1 = Minecraft.getInstance().gameDir.toPath().resolve(parts[0]); + boolean invert = parts.length > 1; + try { + baritone.getExploreProcess().applyJsonFilter(path1, invert); + logDirect("Loaded filter. Inverted: " + invert); + if (invert) { + logDirect("Chunks on this list will be treated as possibly unexplored, all others will be treated as certainly explored"); + } else { + logDirect("Chunks on this list will be treated as certainly explored, all others will be treated as possibly unexplored"); + } + } catch (Exception e) { + e.printStackTrace(); + logDirect("Unable to load " + path1); + } + return true; + } if (msg.equals("reloadall")) { baritone.getWorldProvider().getCurrentWorld().getCachedWorld().reloadAllFromDisk(); logDirect("ok"); @@ -456,14 +478,27 @@ public class ExampleBaritoneControl extends Behavior implements Helper { logDirect("Exploring from " + centerX + "," + centerZ); return true; } + if (msg.equals("blacklist")) { + IGetToBlockProcess proc = baritone.getGetToBlockProcess(); + if (!proc.isActive()) { + logDirect("GetToBlockProcess is not currently active"); + return true; + } + if (proc.blacklistClosest()) { + logDirect("Blacklisted closest instances"); + } else { + logDirect("No known locations, unable to blacklist"); + } + return true; + } if (msg.startsWith("find")) { String blockType = msg.substring(4).trim(); ArrayList locs = baritone.getWorldProvider().getCurrentWorld().getCachedWorld().getLocationsOf(blockType, 1, ctx.playerFeet().getX(), ctx.playerFeet().getZ(), 4); logDirect("Have " + locs.size() + " locations"); for (BlockPos pos : locs) { - Block actually = BlockStateInterface.get(ctx, pos).getBlock(); - if (!ChunkPacker.blockToString(actually).equalsIgnoreCase(blockType)) { - System.out.println("Was looking for " + blockType + " but actually found " + actually + " " + ChunkPacker.blockToString(actually)); + Block actually = ctx.world().getBlockState(pos).getBlock(); + if (!BlockUtils.blockToString(actually).equalsIgnoreCase(blockType)) { + logDebug("Was looking for " + blockType + " but actually found " + actually + " " + BlockUtils.blockToString(actually)); } } return true; @@ -472,13 +507,13 @@ public class ExampleBaritoneControl extends Behavior implements Helper { String[] blockTypes = msg.substring(4).trim().split(" "); try { int quantity = Integer.parseInt(blockTypes[1]); - Block block = ChunkPacker.stringToBlockRequired(blockTypes[0]); + Block block = BlockUtils.stringToBlockRequired(blockTypes[0]); baritone.getMineProcess().mine(quantity, block); logDirect("Will mine " + quantity + " " + blockTypes[0]); return true; } catch (NumberFormatException | ArrayIndexOutOfBoundsException | NullPointerException ex) {} for (String s : blockTypes) { - if (ChunkPacker.stringToBlockNullable(s) == null) { + if (BlockUtils.stringToBlockNullable(s) == null) { logDirect(s + " isn't a valid block name"); return true; } @@ -489,12 +524,7 @@ public class ExampleBaritoneControl extends Behavior implements Helper { return true; } if (msg.equals("click")) { - new Thread(() -> { - try { - Thread.sleep(100); - mc.addScheduledTask(() -> mc.displayGuiScreen(new GuiClick())); - } catch (Exception ignored) {} - }).start(); + baritone.openClick(); logDirect("aight dude"); return true; } @@ -514,9 +544,9 @@ public class ExampleBaritoneControl extends Behavior implements Helper { // for example, "show deaths" waypointType = waypointType.substring(0, waypointType.length() - 1); } - Waypoint.Tag tag = Waypoint.Tag.fromString(waypointType); + IWaypoint.Tag tag = IWaypoint.Tag.fromString(waypointType); if (tag == null) { - logDirect("Not a valid tag. Tags are: " + Arrays.asList(Waypoint.Tag.values()).toString().toLowerCase()); + logDirect("Not a valid tag. Tags are: " + Arrays.asList(IWaypoint.Tag.values()).toString().toLowerCase()); return true; } Set waypoints = baritone.getWorldProvider().getCurrentWorld().getWaypoints().getByTag(tag); @@ -547,21 +577,21 @@ public class ExampleBaritoneControl extends Behavior implements Helper { } name = parts[0]; } - baritone.getWorldProvider().getCurrentWorld().getWaypoints().addWaypoint(new Waypoint(name, Waypoint.Tag.USER, pos)); + baritone.getWorldProvider().getCurrentWorld().getWaypoints().addWaypoint(new Waypoint(name, IWaypoint.Tag.USER, pos)); logDirect("Saved user defined position " + pos + " under name '" + name + "'. Say 'goto " + name + "' to set goal, say 'list user' to list custom waypoints."); return true; } if (msg.startsWith("goto")) { String waypointType = msg.substring(4).trim(); - if (waypointType.endsWith("s") && Waypoint.Tag.fromString(waypointType.substring(0, waypointType.length() - 1)) != null) { + if (waypointType.endsWith("s") && IWaypoint.Tag.fromString(waypointType.substring(0, waypointType.length() - 1)) != null) { // for example, "show deaths" waypointType = waypointType.substring(0, waypointType.length() - 1); } - Waypoint.Tag tag = Waypoint.Tag.fromString(waypointType); + IWaypoint.Tag tag = IWaypoint.Tag.fromString(waypointType); IWaypoint waypoint; if (tag == null) { String mining = waypointType; - Block block = ChunkPacker.stringToBlockNullable(mining); + Block block = BlockUtils.stringToBlockNullable(mining); //logDirect("Not a valid tag. Tags are: " + Arrays.asList(Waypoint.Tag.values()).toString().toLowerCase()); if (block == null) { waypoint = baritone.getWorldProvider().getCurrentWorld().getWaypoints().getAllWaypoints().stream().filter(w -> w.getName().equalsIgnoreCase(mining)).max(Comparator.comparingLong(IWaypoint::getCreationTimestamp)).orElse(null); @@ -584,12 +614,12 @@ public class ExampleBaritoneControl extends Behavior implements Helper { return true; } } - Goal goal = waypoint.getTag() == Waypoint.Tag.BED ? new GoalGetToBlock(waypoint.getLocation()) : new GoalBlock(waypoint.getLocation()); + Goal goal = waypoint.getTag() == IWaypoint.Tag.BED ? new GoalGetToBlock(waypoint.getLocation()) : new GoalBlock(waypoint.getLocation()); customGoalProcess.setGoalAndPath(goal); return true; } if (msg.equals("spawn") || msg.equals("bed")) { - IWaypoint waypoint = baritone.getWorldProvider().getCurrentWorld().getWaypoints().getMostRecentByTag(Waypoint.Tag.BED); + IWaypoint waypoint = baritone.getWorldProvider().getCurrentWorld().getWaypoints().getMostRecentByTag(IWaypoint.Tag.BED); if (waypoint == null) { BlockPos spawnPoint = ctx.player().getBedLocation(); // for some reason the default spawnpoint is underground sometimes @@ -604,12 +634,12 @@ public class ExampleBaritoneControl extends Behavior implements Helper { return true; } if (msg.equals("sethome")) { - baritone.getWorldProvider().getCurrentWorld().getWaypoints().addWaypoint(new Waypoint("", Waypoint.Tag.HOME, ctx.playerFeet())); + baritone.getWorldProvider().getCurrentWorld().getWaypoints().addWaypoint(new Waypoint("", IWaypoint.Tag.HOME, ctx.playerFeet())); logDirect("Saved. Say home to set goal."); return true; } if (msg.equals("home")) { - IWaypoint waypoint = baritone.getWorldProvider().getCurrentWorld().getWaypoints().getMostRecentByTag(Waypoint.Tag.HOME); + IWaypoint waypoint = baritone.getWorldProvider().getCurrentWorld().getWaypoints().getMostRecentByTag(IWaypoint.Tag.HOME); if (waypoint == null) { logDirect("home not saved"); } else { @@ -619,7 +649,8 @@ public class ExampleBaritoneControl extends Behavior implements Helper { } return true; } - if (msg.equals("costs")) { + // this is completely impossible from api + /*if (msg.equals("costs")) { List moves = Stream.of(Moves.values()).map(x -> x.apply0(new CalculationContext(baritone), ctx.playerFeet())).collect(Collectors.toCollection(ArrayList::new)); while (moves.contains(null)) { moves.remove(null); @@ -635,7 +666,7 @@ public class ExampleBaritoneControl extends Behavior implements Helper { logDirect(parts[parts.length - 1] + " " + move.getDest().getX() + "," + move.getDest().getY() + "," + move.getDest().getZ() + " " + strCost); } return true; - } + }*/ if (msg.equals("damn")) { logDirect("daniel"); } diff --git a/src/main/java/baritone/utils/Helper.java b/src/api/java/baritone/api/utils/Helper.java similarity index 90% rename from src/main/java/baritone/utils/Helper.java rename to src/api/java/baritone/api/utils/Helper.java index a4c00d8d7..f05f5ed08 100755 --- a/src/main/java/baritone/utils/Helper.java +++ b/src/api/java/baritone/api/utils/Helper.java @@ -15,9 +15,9 @@ * along with Baritone. If not, see . */ -package baritone.utils; +package baritone.api.utils; -import baritone.Baritone; +import baritone.api.BaritoneAPI; import net.minecraft.client.Minecraft; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TextComponentString; @@ -50,7 +50,7 @@ public interface Helper { * @param message The message to display in chat */ default void logDebug(String message) { - if (!Baritone.settings().chatDebug.value) { + if (!BaritoneAPI.getSettings().chatDebug.value) { //System.out.println("Suppressed debug message:"); //System.out.println(message); return; @@ -67,6 +67,6 @@ public interface Helper { ITextComponent component = MESSAGE_PREFIX.shallowCopy(); component.getStyle().setColor(TextFormatting.GRAY); component.appendSibling(new TextComponentString(" " + message)); - Minecraft.getInstance().addScheduledTask(() -> Baritone.settings().logger.value.accept(component)); + Minecraft.getInstance().addScheduledTask(() -> BaritoneAPI.getSettings().logger.value.accept(component)); } } diff --git a/src/api/java/baritone/api/utils/IPlayerContext.java b/src/api/java/baritone/api/utils/IPlayerContext.java index 7abfee802..f0a5c3314 100644 --- a/src/api/java/baritone/api/utils/IPlayerContext.java +++ b/src/api/java/baritone/api/utils/IPlayerContext.java @@ -71,20 +71,26 @@ public interface IPlayerContext { * @return The position of the highlighted block */ default Optional getSelectedBlock() { - if (objectMouseOver() != null && objectMouseOver().type == RayTraceResult.Type.BLOCK) { - return Optional.of(objectMouseOver().getBlockPos()); + RayTraceResult result = objectMouseOver(); + if (result != null && result.type == RayTraceResult.Type.BLOCK) { + return Optional.of(result.getBlockPos()); } return Optional.empty(); } + default boolean isLookingAt(BlockPos pos) { + return getSelectedBlock().equals(Optional.of(pos)); + } + /** * Returns the entity that the crosshair is currently placed over. Updated once per tick. * * @return The entity */ default Optional getSelectedEntity() { - if (objectMouseOver() != null && objectMouseOver().type == RayTraceResult.Type.ENTITY) { - return Optional.of(objectMouseOver().entity); + RayTraceResult result = objectMouseOver(); + if (result != null && result.type == RayTraceResult.Type.ENTITY) { + return Optional.of(result.entity); } return Optional.empty(); } diff --git a/src/api/java/baritone/api/utils/MyChunkPos.java b/src/api/java/baritone/api/utils/MyChunkPos.java new file mode 100644 index 000000000..5748a13dc --- /dev/null +++ b/src/api/java/baritone/api/utils/MyChunkPos.java @@ -0,0 +1,31 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package baritone.api.utils; + +/** + * Need a non obfed chunkpos that we can load using GSON + */ +public class MyChunkPos { + public int x; + public int z; + + @Override + public String toString() { + return x + ", " + z; + } +} \ No newline at end of file diff --git a/src/api/java/baritone/api/utils/RotationUtils.java b/src/api/java/baritone/api/utils/RotationUtils.java index acdc1c21f..358fcadde 100644 --- a/src/api/java/baritone/api/utils/RotationUtils.java +++ b/src/api/java/baritone/api/utils/RotationUtils.java @@ -160,7 +160,7 @@ public final class RotationUtils { */ public static Optional reachable(EntityPlayerSP entity, BlockPos pos, double blockReachDistance) { IBaritone baritone = BaritoneAPI.getProvider().getBaritoneForPlayer(entity); - if (pos.equals(baritone.getPlayerContext().getSelectedBlock().orElse(null))) { + if (baritone.getPlayerContext().isLookingAt(pos)) { /* * why add 0.0001? * to indicate that we actually have a desired pitch diff --git a/src/api/java/baritone/api/utils/SettingsUtil.java b/src/api/java/baritone/api/utils/SettingsUtil.java index c3608ecae..2a21d4a2c 100644 --- a/src/api/java/baritone/api/utils/SettingsUtil.java +++ b/src/api/java/baritone/api/utils/SettingsUtil.java @@ -18,6 +18,7 @@ package baritone.api.utils; import baritone.api.Settings; +import net.minecraft.block.Block; import net.minecraft.client.Minecraft; import net.minecraft.item.Item; import net.minecraft.util.EnumFacing; @@ -28,23 +29,25 @@ import java.awt.*; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; import java.nio.file.Files; +import java.nio.file.NoSuchFileException; import java.nio.file.Path; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.function.Consumer; import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; -import java.util.stream.Stream; + public class SettingsUtil { - private static final Path SETTINGS_PATH = Minecraft.getInstance().gameDir.toPath().resolve("baritone").resolve("settings.txt"); - private static final Pattern SETTING_PATTERN = Pattern.compile("^(?[^ ]+) +(?[^ ]+)"); // 2 words separated by spaces + private static final Pattern SETTING_PATTERN = Pattern.compile("^(?[^ ]+) +(?.+)"); // key and value split by the first space - private static final Map, SettingsIO> map; private static boolean isComment(String line) { return line.startsWith("#") || line.startsWith("//"); @@ -80,6 +83,8 @@ public class SettingsUtil { ex.printStackTrace(); } }); + } catch (NoSuchFileException ignored) { + System.out.println("Baritone settings file not found, resetting."); } catch (Exception ex) { System.out.println("Exception while reading Baritone settings, some settings may be reset to default values!"); ex.printStackTrace(); @@ -119,11 +124,11 @@ public class SettingsUtil { if (setting.getName().equals("logger")) { return "logger"; } - SettingsIO io = map.get(setting.getValueClass()); + Parser io = Parser.getParser(setting.getType()); if (io == null) { throw new IllegalStateException("Missing " + setting.getValueClass() + " " + setting.getName()); } - return setting.getName() + " " + io.toString.apply(setting.value); + return setting.getName() + " " + io.toString(new ParserContext(setting), setting.value); } public static void parseAndApply(Settings settings, String settingName, String settingValue) throws IllegalStateException, NumberFormatException { @@ -132,46 +137,124 @@ public class SettingsUtil { throw new IllegalStateException("No setting by that name"); } Class intendedType = setting.getValueClass(); - SettingsIO ioMethod = map.get(intendedType); - Object parsed = ioMethod.parser.apply(settingValue); + ISettingParser ioMethod = Parser.getParser(setting.getType()); + Object parsed = ioMethod.parse(new ParserContext(setting), settingValue); if (!intendedType.isInstance(parsed)) { throw new IllegalStateException(ioMethod + " parser returned incorrect type, expected " + intendedType + " got " + parsed + " which is " + parsed.getClass()); } setting.value = parsed; } - private enum SettingsIO { + private interface ISettingParser { + + T parse(ParserContext context, String raw); + + String toString(ParserContext context, T value); + + boolean accepts(Type type); + } + + private static class ParserContext { + + private final Settings.Setting setting; + + public ParserContext(Settings.Setting setting) { + this.setting = setting; + } + + final Settings.Setting getSetting() { + return this.setting; + } + } + + private enum Parser implements ISettingParser { + DOUBLE(Double.class, Double::parseDouble), BOOLEAN(Boolean.class, Boolean::parseBoolean), INTEGER(Integer.class, Integer::parseInt), FLOAT(Float.class, Float::parseFloat), LONG(Long.class, Long::parseLong), + ENUMFACING(EnumFacing.class, EnumFacing::byName), + COLOR( + Color.class, + str -> new Color(Integer.parseInt(str.split(",")[0]), Integer.parseInt(str.split(",")[1]), Integer.parseInt(str.split(",")[2])), + color -> color.getRed() + "," + color.getGreen() + "," + color.getBlue() + ), + BLOCK( + Block.class, + str -> BlockUtils.stringToBlockRequired(str.trim()), + BlockUtils::blockToString + ), + ITEM( + Item.class, + str -> IRegistry.ITEM.get(new ResourceLocation(str.trim())), + item -> IRegistry.ITEM.getKey(item).toString() + ), + LIST() { + @Override + public Object parse(ParserContext context, String raw) { + Type type = ((ParameterizedType) context.getSetting().getType()).getActualTypeArguments()[0]; + Parser parser = Parser.getParser(type); + return Arrays.stream(raw.split(",")) + .map(s -> parser.parse(context, s)) + .collect(Collectors.toList()); + } - ITEM_LIST(ArrayList.class, str -> Stream.of(str.split(",")).map(ResourceLocation::new).map(IRegistry.ITEM::get).collect(Collectors.toCollection(ArrayList::new)), list -> ((ArrayList) list).stream().map(IRegistry.ITEM::getKey).map(ResourceLocation::toString).collect(Collectors.joining(","))), - COLOR(Color.class, str -> new Color(Integer.parseInt(str.split(",")[0]), Integer.parseInt(str.split(",")[1]), Integer.parseInt(str.split(",")[2])), color -> color.getRed() + "," + color.getGreen() + "," + color.getBlue()), - ENUMFACING(EnumFacing.class, EnumFacing::byName); + @Override + public String toString(ParserContext context, Object value) { + Type type = ((ParameterizedType) context.getSetting().getType()).getActualTypeArguments()[0]; + Parser parser = Parser.getParser(type); + return ((List) value).stream() + .map(o -> parser.toString(context, o)) + .collect(Collectors.joining(",")); + } - Class klass; - Function parser; - Function toString; + @Override + public boolean accepts(Type type) { + return List.class.isAssignableFrom(TypeUtils.resolveBaseClass(type)); + } + }; - SettingsIO(Class klass, Function parser) { + private final Class klass; + private final Function parser; + private final Function toString; + + Parser() { + this.klass = null; + this.parser = null; + this.toString = null; + } + + Parser(Class klass, Function parser) { this(klass, parser, Object::toString); } - SettingsIO(Class klass, Function parser, Function toString) { + Parser(Class klass, Function parser, Function toString) { this.klass = klass; this.parser = parser::apply; this.toString = x -> toString.apply((T) x); } - } - static { - HashMap, SettingsIO> tempMap = new HashMap<>(); - for (SettingsIO type : SettingsIO.values()) { - tempMap.put(type.klass, type); + @Override + public Object parse(ParserContext context, String raw) { + return this.parser.apply(raw); + } + + @Override + public String toString(ParserContext context, Object value) { + return this.toString.apply(value); + } + + @Override + public boolean accepts(Type type) { + return type instanceof Class && this.klass.isAssignableFrom((Class) type); + } + + public static Parser getParser(Type type) { + return Arrays.stream(values()) + .filter(parser -> parser.accepts(type)) + .findFirst().orElse(null); } - map = Collections.unmodifiableMap(tempMap); } } diff --git a/src/api/java/baritone/api/utils/TypeUtils.java b/src/api/java/baritone/api/utils/TypeUtils.java new file mode 100644 index 000000000..457cc449a --- /dev/null +++ b/src/api/java/baritone/api/utils/TypeUtils.java @@ -0,0 +1,44 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package baritone.api.utils; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; + +/** + * @author Brady + * @since 4/20/2019 + */ +public final class TypeUtils { + + private TypeUtils() {} + + /** + * Resolves the "base type" for the specified type. For example, if the specified + * type is {@code List}, then {@code List.class} will be returned. If the + * specified type is already a class, then it is directly returned. + * + * @param type The type to resolve + * @return The base class + */ + public static Class resolveBaseClass(Type type) { + return type instanceof Class ? (Class) type + : type instanceof ParameterizedType ? (Class) ((ParameterizedType) type).getRawType() + : null; + } +} diff --git a/src/launch/java/baritone/launch/mixins/MixinChunkRenderContainer.java b/src/launch/java/baritone/launch/mixins/MixinChunkRenderContainer.java index cb699c229..b3c0b6fa8 100644 --- a/src/launch/java/baritone/launch/mixins/MixinChunkRenderContainer.java +++ b/src/launch/java/baritone/launch/mixins/MixinChunkRenderContainer.java @@ -28,8 +28,10 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; -import static org.lwjgl.opengl.GL11.*; -import static org.lwjgl.opengl.GL14.*; +import static org.lwjgl.opengl.GL11.GL_ONE; +import static org.lwjgl.opengl.GL11.GL_ZERO; +import static org.lwjgl.opengl.GL14.GL_CONSTANT_ALPHA; +import static org.lwjgl.opengl.GL14.GL_ONE_MINUS_CONSTANT_ALPHA; @Mixin(ChunkRenderContainer.class) public class MixinChunkRenderContainer { diff --git a/src/main/java/baritone/Baritone.java b/src/main/java/baritone/Baritone.java index f08b4fb16..dd441dfb5 100755 --- a/src/main/java/baritone/Baritone.java +++ b/src/main/java/baritone/Baritone.java @@ -21,6 +21,8 @@ import baritone.api.BaritoneAPI; import baritone.api.IBaritone; import baritone.api.Settings; import baritone.api.event.listener.IEventBus; +import baritone.api.utils.ExampleBaritoneControl; +import baritone.api.utils.Helper; import baritone.api.utils.IPlayerContext; import baritone.behavior.*; import baritone.cache.WorldProvider; @@ -33,8 +35,6 @@ import net.minecraft.client.Minecraft; import java.io.File; import java.io.IOException; import java.nio.file.Files; -import java.util.ArrayList; -import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadPoolExecutor; @@ -67,7 +67,6 @@ public class Baritone implements IBaritone { private GameEventHandler gameEventHandler; - private List behaviors; private PathingBehavior pathingBehavior; private LookBehavior lookBehavior; private MemoryBehavior memoryBehavior; @@ -80,6 +79,8 @@ public class Baritone implements IBaritone { private CustomGoalProcess customGoalProcess; private BuilderProcess builderProcess; private ExploreProcess exploreProcess; + private BackfillProcess backfillProcess; + private FarmProcess farmProcess; private PathingControlManager pathingControlManager; @@ -101,7 +102,6 @@ public class Baritone implements IBaritone { // Define this before behaviors try and get it, or else it will be null and the builds will fail! this.playerContext = PrimaryPlayerContext.INSTANCE; - this.behaviors = new ArrayList<>(); { // the Behavior constructor calls baritone.registerBehavior(this) so this populates the behaviors arraylist pathingBehavior = new PathingBehavior(this); @@ -120,6 +120,8 @@ public class Baritone implements IBaritone { getToBlockProcess = new GetToBlockProcess(this); builderProcess = new BuilderProcess(this); exploreProcess = new ExploreProcess(this); + backfillProcess = new BackfillProcess(this); + farmProcess = new FarmProcess(this); } this.worldProvider = new WorldProvider(); @@ -136,12 +138,7 @@ public class Baritone implements IBaritone { return this.pathingControlManager; } - public List getBehaviors() { - return this.behaviors; - } - public void registerBehavior(Behavior behavior) { - this.behaviors.add(behavior); this.gameEventHandler.registerEventListener(behavior); } @@ -197,6 +194,10 @@ public class Baritone implements IBaritone { return this.mineProcess; } + public FarmProcess getFarmProcess() { + return this.farmProcess; + } + @Override public PathingBehavior getPathingBehavior() { return this.pathingBehavior; @@ -212,6 +213,16 @@ public class Baritone implements IBaritone { return this.gameEventHandler; } + @Override + public void openClick() { + new Thread(() -> { + try { + Thread.sleep(100); + Helper.mc.addScheduledTask(() -> Helper.mc.displayGuiScreen(new GuiClick())); + } catch (Exception ignored) {} + }).start(); + } + public static Settings settings() { return BaritoneAPI.getSettings(); } diff --git a/src/main/java/baritone/behavior/InventoryBehavior.java b/src/main/java/baritone/behavior/InventoryBehavior.java index 120bc7489..03878ee52 100644 --- a/src/main/java/baritone/behavior/InventoryBehavior.java +++ b/src/main/java/baritone/behavior/InventoryBehavior.java @@ -123,27 +123,27 @@ public class InventoryBehavior extends Behavior { public boolean hasGenericThrowaway() { for (Item item : Baritone.settings().acceptableThrowawayItems.value) { - if (throwaway(false, item::equals)) { + if (throwaway(false, stack -> item.equals(stack.getItem()))) { return true; } } return false; } - public boolean selectThrowawayForLocation(int x, int y, int z) { + public boolean selectThrowawayForLocation(boolean select, int x, int y, int z) { IBlockState maybe = baritone.getBuilderProcess().placeAt(x, y, z); - if (maybe != null && throwaway(true, item -> item instanceof ItemBlock && ((ItemBlock) item).getBlock().equals(maybe.getBlock()))) { + if (maybe != null && throwaway(select, stack -> stack.getItem() instanceof ItemBlock && ((ItemBlock) stack.getItem()).getBlock().equals(maybe.getBlock()))) { return true; // gotem } for (Item item : Baritone.settings().acceptableThrowawayItems.value) { - if (throwaway(true, item::equals)) { + if (throwaway(select, stack -> item.equals(stack.getItem()))) { return true; } } return false; } - private boolean throwaway(boolean select, Predicate desired) { + public boolean throwaway(boolean select, Predicate desired) { EntityPlayerSP p = ctx.player(); NonNullList inv = p.inventory.mainInventory; for (byte i = 0; i < 9; i++) { @@ -153,14 +153,14 @@ public class InventoryBehavior extends Behavior { // and then it's called during execution // since this function is never called during cost calculation, we don't need to migrate // acceptableThrowawayItems to the CalculationContext - if (desired.test(item.getItem())) { + if (desired.test(item)) { if (select) { p.inventory.currentItem = i; } return true; } } - if (desired.test(p.inventory.offHandInventory.get(0).getItem())) { + if (desired.test(p.inventory.offHandInventory.get(0))) { // main hand takes precedence over off hand // that means that if we have block A selected in main hand and block B in off hand, right clicking places block B // we've already checked above ^ and the main hand can't possible have an acceptablethrowawayitem diff --git a/src/main/java/baritone/behavior/MemoryBehavior.java b/src/main/java/baritone/behavior/MemoryBehavior.java index 50beda0f8..d98e32376 100644 --- a/src/main/java/baritone/behavior/MemoryBehavior.java +++ b/src/main/java/baritone/behavior/MemoryBehavior.java @@ -18,13 +18,13 @@ package baritone.behavior; import baritone.Baritone; +import baritone.api.cache.Waypoint; import baritone.api.event.events.BlockInteractEvent; import baritone.api.event.events.PacketEvent; import baritone.api.event.events.PlayerUpdateEvent; import baritone.api.event.events.TickEvent; import baritone.api.event.events.type.EventState; import baritone.cache.ContainerMemory; -import baritone.cache.Waypoint; import baritone.utils.BlockStateInterface; import net.minecraft.block.Block; import net.minecraft.block.BlockBed; diff --git a/src/main/java/baritone/behavior/PathingBehavior.java b/src/main/java/baritone/behavior/PathingBehavior.java index 00ac5a4cb..fbe48ad80 100644 --- a/src/main/java/baritone/behavior/PathingBehavior.java +++ b/src/main/java/baritone/behavior/PathingBehavior.java @@ -25,6 +25,7 @@ import baritone.api.pathing.goals.Goal; import baritone.api.pathing.goals.GoalXZ; import baritone.api.process.PathingCommand; import baritone.api.utils.BetterBlockPos; +import baritone.api.utils.Helper; import baritone.api.utils.PathCalculationResult; import baritone.api.utils.interfaces.IGoalRenderPos; import baritone.pathing.calc.AStarPathFinder; @@ -32,7 +33,6 @@ import baritone.pathing.calc.AbstractNodeCostSearch; import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.MovementHelper; import baritone.pathing.path.PathExecutor; -import baritone.utils.Helper; import baritone.utils.PathRenderer; import baritone.utils.PathingCommandContext; import baritone.utils.pathing.Favoring; @@ -195,7 +195,9 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, current.onTick(); return; } - current = current.trySplice(next); + if (Baritone.settings().splicePath.value) { + current = current.trySplice(next); + } if (next != null && current.getPath().getDest().equals(next.getPath().getDest())) { next = null; } @@ -350,7 +352,8 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, } } - public void forceCancel() { // NOT exposed on public api + @Override + public void forceCancel() { // exposed on public api because :sob: cancelEverything(); secretInternalSegmentCancel(); synchronized (pathCalcLock) { @@ -358,11 +361,11 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, } } - public void secretCursedFunctionDoNotCall(IPath path) { + /*public void secretCursedFunctionDoNotCall(IPath path) { synchronized (pathPlanLock) { current = new PathExecutor(this, path); } - } + }*/ public CalculationContext secretInternalGetCalculationContext() { return context; diff --git a/src/main/java/baritone/cache/CachedChunk.java b/src/main/java/baritone/cache/CachedChunk.java index fa99b38a8..bdffec94e 100644 --- a/src/main/java/baritone/cache/CachedChunk.java +++ b/src/main/java/baritone/cache/CachedChunk.java @@ -17,6 +17,7 @@ package baritone.cache; +import baritone.api.utils.BlockUtils; import baritone.utils.pathing.PathingBlockType; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import net.minecraft.block.Block; @@ -113,7 +114,7 @@ public final class CachedChunk { temp.add(Blocks.GREEN_BED); temp.add(Blocks.RED_BED); temp.add(Blocks.BLACK_BED); - + temp.add(Blocks.DRAGON_EGG); temp.add(Blocks.JUKEBOX); temp.add(Blocks.END_GATEWAY); @@ -212,7 +213,7 @@ public final class CachedChunk { if (special != null) { String str = special.get(index); if (str != null) { - return ChunkPacker.stringToBlockRequired(str).getDefaultState(); + return BlockUtils.stringToBlockRequired(str).getDefaultState(); } } diff --git a/src/main/java/baritone/cache/CachedRegion.java b/src/main/java/baritone/cache/CachedRegion.java index d395f168a..630dcc9e5 100644 --- a/src/main/java/baritone/cache/CachedRegion.java +++ b/src/main/java/baritone/cache/CachedRegion.java @@ -19,6 +19,7 @@ package baritone.cache; import baritone.Baritone; import baritone.api.cache.ICachedRegion; +import baritone.api.utils.BlockUtils; import net.minecraft.block.state.IBlockState; import net.minecraft.util.math.BlockPos; @@ -149,7 +150,7 @@ public final class CachedRegion implements ICachedRegion { for (int z = 0; z < 32; z++) { if (chunks[x][z] != null) { for (int i = 0; i < 256; i++) { - out.writeUTF(ChunkPacker.blockToString(chunks[x][z].getOverview()[i].getBlock())); + out.writeUTF(BlockUtils.blockToString(chunks[x][z].getOverview()[i].getBlock())); } } } @@ -240,7 +241,7 @@ public final class CachedRegion implements ICachedRegion { for (int z = 0; z < 32; z++) { if (present[x][z]) { for (int i = 0; i < 256; i++) { - overview[x][z][i] = ChunkPacker.stringToBlockRequired(in.readUTF()).getDefaultState(); + overview[x][z][i] = BlockUtils.stringToBlockRequired(in.readUTF()).getDefaultState(); } } } @@ -255,7 +256,7 @@ public final class CachedRegion implements ICachedRegion { int numSpecialBlockTypes = in.readShort() & 0xffff; for (int i = 0; i < numSpecialBlockTypes; i++) { String blockName = in.readUTF(); - ChunkPacker.stringToBlockRequired(blockName); + BlockUtils.stringToBlockRequired(blockName); List locs = new ArrayList<>(); location[x][z].put(blockName, locs); int numLocations = in.readShort() & 0xffff; diff --git a/src/main/java/baritone/cache/CachedWorld.java b/src/main/java/baritone/cache/CachedWorld.java index 949f818c9..7c8e4291e 100644 --- a/src/main/java/baritone/cache/CachedWorld.java +++ b/src/main/java/baritone/cache/CachedWorld.java @@ -22,7 +22,7 @@ import baritone.api.BaritoneAPI; import baritone.api.IBaritone; import baritone.api.cache.ICachedWorld; import baritone.api.cache.IWorldData; -import baritone.utils.Helper; +import baritone.api.utils.Helper; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import net.minecraft.util.math.BlockPos; diff --git a/src/main/java/baritone/cache/ChunkPacker.java b/src/main/java/baritone/cache/ChunkPacker.java index 6fc332bd3..b8e7cc1e3 100644 --- a/src/main/java/baritone/cache/ChunkPacker.java +++ b/src/main/java/baritone/cache/ChunkPacker.java @@ -17,15 +17,14 @@ package baritone.cache; +import baritone.api.utils.BlockUtils; import baritone.pathing.movement.MovementHelper; import baritone.utils.pathing.PathingBlockType; import net.minecraft.block.*; import net.minecraft.block.state.IBlockState; import net.minecraft.init.Blocks; -import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; -import net.minecraft.util.registry.IRegistry; import net.minecraft.world.chunk.BlockStateContainer; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.ChunkSection; @@ -38,8 +37,6 @@ import java.util.*; */ public final class ChunkPacker { - private static final Map resourceCache = new HashMap<>(); - private ChunkPacker() {} public static CachedChunk pack(Chunk chunk) { @@ -77,7 +74,7 @@ public final class ChunkPacker { bitSet.set(index + 1, bits[1]); Block block = state.getBlock(); if (CachedChunk.BLOCKS_TO_KEEP_TRACK_OF.contains(block)) { - String name = blockToString(block); + String name = BlockUtils.blockToString(block); specialBlocks.computeIfAbsent(name, b -> new ArrayList<>()).add(new BlockPos(x, y, z)); } } @@ -92,8 +89,7 @@ public final class ChunkPacker { IBlockState[] blocks = new IBlockState[256]; for (int z = 0; z < 16; z++) { - https: -//www.ibm.com/developerworks/library/j-perry-writing-good-java-code/index.html + https://www.ibm.com/developerworks/library/j-perry-writing-good-java-code/index.html for (int x = 0; x < 16; x++) { for (int y = 255; y >= 0; y--) { int index = CachedChunk.getPositionIndex(x, y, z); @@ -108,29 +104,6 @@ public final class ChunkPacker { return new CachedChunk(chunk.x, chunk.z, bitSet, blocks, specialBlocks, System.currentTimeMillis()); } - public static String blockToString(Block block) { - ResourceLocation loc = IRegistry.BLOCK.getKey(block); - String name = loc.getPath(); // normally, only write the part after the minecraft: - if (!loc.getNamespace().equals("minecraft")) { - // Baritone is running on top of forge with mods installed, perhaps? - name = loc.toString(); // include the namespace with the colon - } - return name; - } - - public static Block stringToBlockRequired(String name) { - if (name.equals("lit_redstone_ore")) { - return stringToBlockRequired("redstone_ore"); - } - Block block = stringToBlockNullable(name); - Objects.requireNonNull(block); - return block; - } - - public static Block stringToBlockNullable(String name) { - return resourceCache.computeIfAbsent(name, n -> IRegistry.BLOCK.get(ResourceLocation.tryCreate(n.contains(":") ? n : "minecraft:" + n))); - } - private static PathingBlockType getPathingBlockType(IBlockState state, Chunk chunk, int x, int y, int z) { Block block = state.getBlock(); if (MovementHelper.isWater(state)) { @@ -139,6 +112,14 @@ public final class ChunkPacker { if (MovementHelper.possiblyFlowing(state)) { return PathingBlockType.AVOID; } + if ( + (x != 15 && MovementHelper.possiblyFlowing(chunk.getBlockState(x + 1, y, z))) + || (x != 0 && MovementHelper.possiblyFlowing(chunk.getBlockState(x - 1, y, z))) + || (z != 15 && MovementHelper.possiblyFlowing(chunk.getBlockState(x, y, z + 1))) + || (z != 0 && MovementHelper.possiblyFlowing(chunk.getBlockState(x, y, z - 1))) + ) { + return PathingBlockType.AVOID; + } if (x == 0 || x == 15 || z == 0 || z == 15) { Vec3d flow = state.getFluidState().getFlow(chunk.getWorld(), new BlockPos(x + chunk.x << 4, y, z + chunk.z << 4)); if (flow.x != 0.0 || flow.z != 0.0) { @@ -146,9 +127,6 @@ public final class ChunkPacker { } return PathingBlockType.AVOID; } - if (MovementHelper.possiblyFlowing(chunk.getBlockState(x + 1, y, z)) || MovementHelper.possiblyFlowing(chunk.getBlockState(x - 1, y, z)) || MovementHelper.possiblyFlowing(chunk.getBlockState(x, y, z + 1)) || MovementHelper.possiblyFlowing(chunk.getBlockState(x, y, z - 1))) { - return PathingBlockType.AVOID; - } return PathingBlockType.WATER; } diff --git a/src/main/java/baritone/cache/WaypointCollection.java b/src/main/java/baritone/cache/WaypointCollection.java index ef3196025..18b13b89b 100644 --- a/src/main/java/baritone/cache/WaypointCollection.java +++ b/src/main/java/baritone/cache/WaypointCollection.java @@ -19,6 +19,7 @@ package baritone.cache; import baritone.api.cache.IWaypoint; import baritone.api.cache.IWaypointCollection; +import baritone.api.cache.Waypoint; import net.minecraft.util.math.BlockPos; import java.io.*; diff --git a/src/main/java/baritone/cache/WorldProvider.java b/src/main/java/baritone/cache/WorldProvider.java index 329e35a8d..e5a924268 100644 --- a/src/main/java/baritone/cache/WorldProvider.java +++ b/src/main/java/baritone/cache/WorldProvider.java @@ -19,7 +19,7 @@ package baritone.cache; import baritone.Baritone; import baritone.api.cache.IWorldProvider; -import baritone.utils.Helper; +import baritone.api.utils.Helper; import baritone.utils.accessor.IAnvilChunkLoader; import baritone.utils.accessor.IChunkProviderServer; import net.minecraft.server.integrated.IntegratedServer; diff --git a/src/main/java/baritone/event/GameEventHandler.java b/src/main/java/baritone/event/GameEventHandler.java index 6d947a9a8..5519d5023 100644 --- a/src/main/java/baritone/event/GameEventHandler.java +++ b/src/main/java/baritone/event/GameEventHandler.java @@ -22,9 +22,9 @@ import baritone.api.event.events.*; import baritone.api.event.events.type.EventState; import baritone.api.event.listener.IEventBus; import baritone.api.event.listener.IGameEventListener; +import baritone.api.utils.Helper; import baritone.cache.WorldProvider; import baritone.utils.BlockStateInterface; -import baritone.utils.Helper; import net.minecraft.world.World; import net.minecraft.world.chunk.Chunk; diff --git a/src/main/java/baritone/pathing/calc/AbstractNodeCostSearch.java b/src/main/java/baritone/pathing/calc/AbstractNodeCostSearch.java index a7d104cf1..302827481 100644 --- a/src/main/java/baritone/pathing/calc/AbstractNodeCostSearch.java +++ b/src/main/java/baritone/pathing/calc/AbstractNodeCostSearch.java @@ -22,9 +22,9 @@ import baritone.api.pathing.calc.IPath; import baritone.api.pathing.calc.IPathFinder; import baritone.api.pathing.goals.Goal; import baritone.api.utils.BetterBlockPos; +import baritone.api.utils.Helper; import baritone.api.utils.PathCalculationResult; import baritone.pathing.movement.CalculationContext; -import baritone.utils.Helper; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import java.util.Optional; @@ -186,7 +186,7 @@ public abstract class AbstractNodeCostSearch implements IPathFinder, Helper { } protected Optional bestSoFar(boolean logInfo, int numNodes) { - if (startNode == null || bestSoFar == null) { + if (startNode == null) { return Optional.empty(); } double bestDist = 0; diff --git a/src/main/java/baritone/pathing/calc/Path.java b/src/main/java/baritone/pathing/calc/Path.java index 374417438..a3f9dd22e 100644 --- a/src/main/java/baritone/pathing/calc/Path.java +++ b/src/main/java/baritone/pathing/calc/Path.java @@ -21,11 +21,11 @@ import baritone.api.pathing.calc.IPath; import baritone.api.pathing.goals.Goal; import baritone.api.pathing.movement.IMovement; import baritone.api.utils.BetterBlockPos; +import baritone.api.utils.Helper; import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.Movement; import baritone.pathing.movement.Moves; import baritone.pathing.path.CutoffPath; -import baritone.utils.Helper; import baritone.utils.pathing.PathBase; import java.util.ArrayList; diff --git a/src/main/java/baritone/pathing/movement/Movement.java b/src/main/java/baritone/pathing/movement/Movement.java index 5da08a3f6..20fa7386b 100644 --- a/src/main/java/baritone/pathing/movement/Movement.java +++ b/src/main/java/baritone/pathing/movement/Movement.java @@ -17,18 +17,20 @@ package baritone.pathing.movement; +import baritone.Baritone; import baritone.api.IBaritone; import baritone.api.pathing.movement.IMovement; import baritone.api.pathing.movement.MovementStatus; import baritone.api.utils.*; import baritone.api.utils.input.Input; import baritone.utils.BlockStateInterface; +import net.minecraft.entity.item.EntityFallingBlock; import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import java.util.ArrayList; import java.util.List; -import java.util.Objects; import java.util.Optional; public abstract class Movement implements IMovement, MovementHelper { @@ -139,6 +141,9 @@ public abstract class Movement implements IMovement, MovementHelper { } boolean somethingInTheWay = false; for (BetterBlockPos blockPos : positionsToBreak) { + if (!ctx.world().getEntitiesWithinAABB(EntityFallingBlock.class, new AxisAlignedBB(0, 0, 0, 1, 1.1, 1).offset(blockPos)).isEmpty() && Baritone.settings().pauseMiningForFallingBlocks.value) { + return false; + } if (!MovementHelper.canWalkThrough(ctx, blockPos)) { // can't break air, so don't try somethingInTheWay = true; Optional reachable = RotationUtils.reachable(ctx.player(), blockPos, ctx.playerController().getBlockReachDistance()); @@ -146,7 +151,7 @@ public abstract class Movement implements IMovement, MovementHelper { Rotation rotTowardsBlock = reachable.get(); MovementHelper.switchToBestToolFor(ctx, BlockStateInterface.get(ctx, blockPos)); state.setTarget(new MovementState.MovementTarget(rotTowardsBlock, true)); - if (Objects.equals(ctx.getSelectedBlock().orElse(null), blockPos) || ctx.playerRotations().isReallyCloseTo(rotTowardsBlock)) { + if (ctx.isLookingAt(blockPos) || ctx.playerRotations().isReallyCloseTo(rotTowardsBlock)) { state.setInput(Input.CLICK_LEFT, true); } return false; @@ -269,4 +274,8 @@ public abstract class Movement implements IMovement, MovementHelper { } return toWalkIntoCached; } + + public BlockPos[] toBreakAll() { + return positionsToBreak; + } } diff --git a/src/main/java/baritone/pathing/movement/MovementHelper.java b/src/main/java/baritone/pathing/movement/MovementHelper.java index 77b4e985c..e67fc9d24 100644 --- a/src/main/java/baritone/pathing/movement/MovementHelper.java +++ b/src/main/java/baritone/pathing/movement/MovementHelper.java @@ -25,7 +25,6 @@ import baritone.api.utils.*; import baritone.api.utils.input.Input; import baritone.pathing.movement.MovementState.MovementTarget; import baritone.utils.BlockStateInterface; -import baritone.utils.Helper; import baritone.utils.ToolSet; import net.minecraft.block.*; import net.minecraft.block.state.IBlockState; @@ -59,11 +58,27 @@ public interface MovementHelper extends ActionCosts, Helper { return b == Blocks.ICE // ice becomes water, and water can mess up the path || b instanceof BlockSilverfish // obvious reasons // call context.get directly with x,y,z. no need to make 5 new BlockPos for no reason - || !bsi.get0(x, y + 1, z).getFluidState().isEmpty()//don't break anything touching liquid on any side - || !bsi.get0(x + 1, y, z).getFluidState().isEmpty() - || !bsi.get0(x - 1, y, z).getFluidState().isEmpty() - || !bsi.get0(x, y, z + 1).getFluidState().isEmpty() - || !bsi.get0(x, y, z - 1).getFluidState().isEmpty(); + || avoidAdjacentBreaking(bsi, x, y + 1, z, true) + || avoidAdjacentBreaking(bsi, x + 1, y, z, false) + || avoidAdjacentBreaking(bsi, x - 1, y, z, false) + || avoidAdjacentBreaking(bsi, x, y, z + 1, false) + || avoidAdjacentBreaking(bsi, x, y, z - 1, false); + } + + static boolean avoidAdjacentBreaking(BlockStateInterface bsi, int x, int y, int z, boolean directlyAbove) { + // returns true if you should avoid breaking a block that's adjacent to this one (e.g. lava that will start flowing if you give it a path) + // this is only called for north, south, east, west, and up. this is NOT called for down. + // we assume that it's ALWAYS okay to break the block thats ABOVE liquid + IBlockState state = bsi.get0(x, y, z); + Block block = state.getBlock(); + if (!directlyAbove // it is fine to mine a block that has a falling block directly above, this (the cost of breaking the stacked fallings) is included in cost calculations + // therefore if directlyAbove is true, we will actually ignore if this is falling + && block instanceof BlockFalling // obviously, this check is only valid for falling blocks + && Baritone.settings().avoidUpdatingFallingBlocks.value // and if the setting is enabled + && BlockFalling.canFallThrough(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 + } + return state.getFluidState().isEmpty(); } static boolean canWalkThrough(IPlayerContext ctx, BetterBlockPos pos) { @@ -82,6 +97,9 @@ public interface MovementHelper extends ActionCosts, Helper { if (block == Blocks.FIRE || block == Blocks.TRIPWIRE || block == Blocks.COBWEB || block == Blocks.END_PORTAL || block == Blocks.COCOA || block instanceof BlockSkull || block == Blocks.BUBBLE_COLUMN || block instanceof BlockShulkerBox || block instanceof BlockSlab || block instanceof BlockTrapDoor) { return false; } + if (Baritone.settings().blocksToAvoid.value.contains(block)) { + return false; + } if (block instanceof BlockDoor || block instanceof BlockFenceGate) { // 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 @@ -319,6 +337,10 @@ public interface MovementHelper extends ActionCosts, Helper { return canWalkOn(new BlockStateInterface(ctx), pos.x, pos.y, pos.z, state); } + static boolean canWalkOn(IPlayerContext ctx, BlockPos pos) { + return canWalkOn(new BlockStateInterface(ctx), pos.getX(), pos.getY(), pos.getZ()); + } + static boolean canWalkOn(IPlayerContext ctx, BetterBlockPos pos) { return canWalkOn(new BlockStateInterface(ctx), pos.x, pos.y, pos.z); } @@ -353,6 +375,9 @@ public interface MovementHelper extends ActionCosts, Helper { static double getMiningDurationTicks(CalculationContext context, int x, int y, int z, IBlockState state, boolean includeFalling) { Block block = state.getBlock(); if (!canWalkThrough(context.bsi, x, y, z, state)) { + if (!state.getFluidState().isEmpty()) { + return COST_INF; + } double mult = context.breakCostMultiplierAt(x, y, z); if (mult >= COST_INF) { return COST_INF; @@ -360,16 +385,11 @@ public interface MovementHelper extends ActionCosts, Helper { if (avoidBreaking(context.bsi, x, y, z, state)) { return COST_INF; } - if (!state.getFluidState().isEmpty()) { - return COST_INF; - } - double m = Blocks.CRAFTING_TABLE.equals(block) ? 10 : 1; // TODO see if this is still necessary. it's from MineBot when we wanted to penalize breaking its crafting table double strVsBlock = context.toolSet.getStrVsBlock(state); if (strVsBlock <= 0) { return COST_INF; } - - double result = m / strVsBlock; + double result = 1 / strVsBlock; result += context.breakBlockAdditionalCost; result *= mult; if (includeFalling) { @@ -494,8 +514,8 @@ public interface MovementHelper extends ActionCosts, Helper { for (int i = 0; i < 5; i++) { BlockPos against1 = placeAt.offset(HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i]); if (MovementHelper.canPlaceAgainst(ctx, against1)) { - if (!((Baritone) baritone).getInventoryBehavior().selectThrowawayForLocation(placeAt.getX(), placeAt.getY(), placeAt.getZ())) { // get ready to place a throwaway block - Helper.HELPER.logDebug("bb pls get me some blocks. dirt or cobble"); + if (!((Baritone) baritone).getInventoryBehavior().selectThrowawayForLocation(false, placeAt.getX(), placeAt.getY(), placeAt.getZ())) { // get ready to place a throwaway block + Helper.HELPER.logDebug("bb pls get me some blocks. dirt, netherrack, cobble"); state.setStatus(MovementStatus.UNREACHABLE); return PlaceResult.NO_OPTION; } @@ -521,10 +541,15 @@ public interface MovementHelper extends ActionCosts, Helper { EnumFacing side = ctx.objectMouseOver().sideHit; // only way for selectedBlock.equals(placeAt) to be true is if it's replacable if (selectedBlock.equals(placeAt) || (MovementHelper.canPlaceAgainst(ctx, selectedBlock) && selectedBlock.offset(side).equals(placeAt))) { + ((Baritone) baritone).getInventoryBehavior().selectThrowawayForLocation(true, placeAt.getX(), placeAt.getY(), placeAt.getZ()); return PlaceResult.READY_TO_PLACE; } } - return found ? PlaceResult.ATTEMPTING : PlaceResult.NO_OPTION; + if (found) { + ((Baritone) baritone).getInventoryBehavior().selectThrowawayForLocation(true, placeAt.getX(), placeAt.getY(), placeAt.getZ()); + return PlaceResult.ATTEMPTING; + } + return PlaceResult.NO_OPTION; } enum PlaceResult { diff --git a/src/main/java/baritone/pathing/movement/movements/MovementAscend.java b/src/main/java/baritone/pathing/movement/movements/MovementAscend.java index 2ba10f706..b37fd4d00 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementAscend.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementAscend.java @@ -197,7 +197,7 @@ public class MovementAscend extends Movement { if (headBonkClear()) { return state.setInput(Input.JUMP, true); } - + if (flatDistToNext > 1.2 || sideDist > 0.2) { return state; } diff --git a/src/main/java/baritone/pathing/movement/movements/MovementFall.java b/src/main/java/baritone/pathing/movement/movements/MovementFall.java index 5aeb73e47..fc54a41f8 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementFall.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementFall.java @@ -40,7 +40,6 @@ import net.minecraft.init.Items; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3i; @@ -94,8 +93,7 @@ public class MovementFall extends Movement { targetRotation = new Rotation(toDest.getYaw(), 90.0F); - RayTraceResult trace = ctx.objectMouseOver(); - if (trace != null && trace.type == RayTraceResult.Type.BLOCK && (trace.getBlockPos().equals(dest) || trace.getBlockPos().equals(dest.down()))) { + if (ctx.isLookingAt(dest) || ctx.isLookingAt(dest.down())) { state.setInput(Input.CLICK_RIGHT, true); } } diff --git a/src/main/java/baritone/pathing/movement/movements/MovementParkour.java b/src/main/java/baritone/pathing/movement/movements/MovementParkour.java index 3df9e0448..613948da8 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementParkour.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementParkour.java @@ -107,7 +107,9 @@ public class MovementParkour extends Movement { return; } } - if (MovementHelper.canWalkOn(context.bsi, x + xDiff * i, y - 1, z + zDiff * i)) { + IBlockState landingOn = context.bsi.get0(x + xDiff * i, y - 1, z + zDiff * i); + // farmland needs to be canwalkon otherwise farm can never work at all, but we want to specifically disallow ending a jumy on farmland haha + if (landingOn.getBlock() != Blocks.FARMLAND && MovementHelper.canWalkOn(context.bsi, x + xDiff * i, y - 1, z + zDiff * i, landingOn)) { res.x = x + xDiff * i; res.y = y; res.z = z + zDiff * i; diff --git a/src/main/java/baritone/pathing/movement/movements/MovementPillar.java b/src/main/java/baritone/pathing/movement/movements/MovementPillar.java index 7fee89217..93ca58e08 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementPillar.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementPillar.java @@ -209,7 +209,7 @@ public class MovementPillar extends Movement { return state; } else { // Get ready to place a throwaway block - if (!((Baritone) baritone).getInventoryBehavior().selectThrowawayForLocation(src.x, src.y, src.z)) { + if (!((Baritone) baritone).getInventoryBehavior().selectThrowawayForLocation(true, src.x, src.y, src.z)) { return state.setStatus(MovementStatus.UNREACHABLE); } diff --git a/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java b/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java index 045c988e7..62ebd41f1 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java @@ -38,8 +38,6 @@ import net.minecraft.state.properties.SlabType; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; -import java.util.Objects; - public class MovementTraverse extends Movement { /** @@ -249,12 +247,13 @@ public class MovementTraverse extends Movement { if (wasTheBridgeBlockAlwaysThere && (!MovementHelper.isLiquid(ctx, ctx.playerFeet()) || Baritone.settings().sprintInWater.value) && (!MovementHelper.avoidWalkingInto(intoBelow) || MovementHelper.isWater(intoBelow)) && !MovementHelper.avoidWalkingInto(intoAbove)) { state.setInput(Input.SPRINT, true); } - Block destDown = BlockStateInterface.get(ctx, dest.down()).getBlock(); - if (whereAmI.getY() != dest.getY() && ladder && (destDown == Blocks.VINE || destDown == Blocks.LADDER)) { - new MovementPillar(baritone, dest.down(), dest).updateState(state); // i'm sorry - return state; + + IBlockState destDown = BlockStateInterface.get(ctx, dest.down()); + BlockPos against = positionsToBreak[0]; + if (whereAmI.getY() != dest.getY() && ladder && (destDown.getBlock() == Blocks.VINE || destDown.getBlock() == Blocks.LADDER)) { + against = destDown.getBlock() == Blocks.VINE ? MovementPillar.getAgainst(new CalculationContext(baritone), dest.down()) : dest.offset(destDown.get(BlockLadder.FACING).getOpposite()); } - MovementHelper.moveTowards(ctx, state, positionsToBreak[0]); + MovementHelper.moveTowards(ctx, state, against); return state; } else { wasTheBridgeBlockAlwaysThere = false; @@ -315,7 +314,7 @@ public class MovementTraverse extends Movement { } else { state.setTarget(new MovementState.MovementTarget(backToFace, true)); } - if (Objects.equals(ctx.getSelectedBlock().orElse(null), goalLook)) { + if (ctx.isLookingAt(goalLook)) { return state.setInput(Input.CLICK_RIGHT, true); // wait to right click until we are able to place } // Out.log("Trying to look at " + goalLook + ", actually looking at" + Baritone.whatAreYouLookingAt()); diff --git a/src/main/java/baritone/pathing/path/PathExecutor.java b/src/main/java/baritone/pathing/path/PathExecutor.java index cc17ef8c2..937c09db6 100644 --- a/src/main/java/baritone/pathing/path/PathExecutor.java +++ b/src/main/java/baritone/pathing/path/PathExecutor.java @@ -23,10 +23,7 @@ import baritone.api.pathing.movement.ActionCosts; import baritone.api.pathing.movement.IMovement; import baritone.api.pathing.movement.MovementStatus; import baritone.api.pathing.path.IPathExecutor; -import baritone.api.utils.BetterBlockPos; -import baritone.api.utils.IPlayerContext; -import baritone.api.utils.RotationUtils; -import baritone.api.utils.VecUtils; +import baritone.api.utils.*; import baritone.api.utils.input.Input; import baritone.behavior.PathingBehavior; import baritone.pathing.calc.AbstractNodeCostSearch; @@ -35,9 +32,7 @@ import baritone.pathing.movement.Movement; import baritone.pathing.movement.MovementHelper; import baritone.pathing.movement.movements.*; import baritone.utils.BlockStateInterface; -import baritone.utils.Helper; import net.minecraft.init.Blocks; -import net.minecraft.init.Fluids; import net.minecraft.util.Tuple; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; @@ -441,7 +436,10 @@ public class PathExecutor implements IPathExecutor, Helper { IMovement prev = path.movements().get(pathPosition - 1); if (prev instanceof MovementDescend && prev.getDirection().up().equals(current.getDirection().down())) { BlockPos center = current.getSrc().up(); - if (ctx.player().posY >= center.getY()) { // playerFeet adds 0.1251 to account for soul sand + // playerFeet adds 0.1251 to account for soul sand + // farmland is 0.9375 + // 0.07 is to account for farmland + if (ctx.player().posY >= center.getY() - 0.07) { behavior.baritone.getInputOverrideHandler().setInputForceState(Input.JUMP, false); return true; } @@ -566,7 +564,10 @@ public class PathExecutor implements IPathExecutor, Helper { if (next instanceof MovementDescend && next.getDirection().equals(current.getDirection())) { return true; } - if (next instanceof MovementTraverse && next.getDirection().down().equals(current.getDirection()) && MovementHelper.canWalkOn(ctx, next.getDest().down())) { + if (!MovementHelper.canWalkOn(ctx, current.getDest().add(current.getDirection()))) { + return false; + } + if (next instanceof MovementTraverse && next.getDirection().down().equals(current.getDirection())) { return true; } return next instanceof MovementDiagonal && Baritone.settings().allowOvershootDiagonalDescend.value; @@ -608,7 +609,7 @@ public class PathExecutor implements IPathExecutor, Helper { ret.costEstimateIndex = costEstimateIndex; ret.ticksOnCurrent = ticksOnCurrent; return ret; - }).orElse(cutIfTooLong()); + }).orElseGet(this::cutIfTooLong); // dont actually call cutIfTooLong every tick if we won't actually use it, use a method reference } private PathExecutor cutIfTooLong() { diff --git a/src/main/java/baritone/process/BackfillProcess.java b/src/main/java/baritone/process/BackfillProcess.java new file mode 100644 index 000000000..8ed9b3c94 --- /dev/null +++ b/src/main/java/baritone/process/BackfillProcess.java @@ -0,0 +1,140 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package baritone.process; + +import baritone.Baritone; +import baritone.api.process.PathingCommand; +import baritone.api.process.PathingCommandType; +import baritone.api.utils.input.Input; +import baritone.pathing.movement.Movement; +import baritone.pathing.movement.MovementHelper; +import baritone.pathing.movement.MovementState; +import baritone.pathing.path.PathExecutor; +import baritone.utils.BaritoneProcessHelper; +import net.minecraft.block.state.IBlockState; +import net.minecraft.init.Blocks; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.chunk.EmptyChunk; + +import java.util.*; +import java.util.stream.Collectors; + +public class BackfillProcess extends BaritoneProcessHelper { + + public HashMap blocksToReplace = new HashMap<>(); + + public BackfillProcess(Baritone baritone) { + super(baritone); + } + + @Override + public boolean isActive() { + if (ctx.player() == null || ctx.world() == null) { + return false; + } + if (!Baritone.settings().backfill.value) { + return false; + } + if (Baritone.settings().allowParkour.value) { + logDirect("Backfill cannot be used with allowParkour true"); + Baritone.settings().backfill.value = false; + return false; + } + amIBreakingABlockHMMMMMMM(); + for (BlockPos pos : new ArrayList<>(blocksToReplace.keySet())) { + if (ctx.world().getChunk(pos) instanceof EmptyChunk) { + blocksToReplace.remove(pos); + } + } + baritone.getInputOverrideHandler().clearAllKeys(); + + return !toFillIn().isEmpty(); + } + + @Override + public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) { + if (!isSafeToCancel) { + return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE); + } + baritone.getInputOverrideHandler().clearAllKeys(); + for (BlockPos toPlace : toFillIn()) { + MovementState fake = new MovementState(); + switch (MovementHelper.attemptToPlaceABlock(fake, baritone, toPlace, false)) { + case NO_OPTION: + continue; + case READY_TO_PLACE: + baritone.getInputOverrideHandler().setInputForceState(Input.CLICK_RIGHT, true); + return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE); + case ATTEMPTING: + // patience + baritone.getLookBehavior().updateTarget(fake.getTarget().getRotation().get(), true); + return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE); + } + } + return new PathingCommand(null, PathingCommandType.DEFER); // cede to other process + } + + public void amIBreakingABlockHMMMMMMM() { + if (!ctx.getSelectedBlock().isPresent()) { + return; + } + blocksToReplace.put(ctx.getSelectedBlock().get(), ctx.world().getBlockState(ctx.getSelectedBlock().get())); + } + + public List toFillIn() { + return blocksToReplace + .keySet() + .stream() + .filter(pos -> ctx.world().getBlockState(pos).getBlock() == Blocks.AIR) + .filter(pos -> baritone.getBuilderProcess().placementPlausible(pos, Blocks.DIRT.getDefaultState())) + .filter(pos -> !partOfCurrentMovement(pos)) + .sorted(Comparator.comparingDouble(ctx.player()::getDistanceSq).reversed()) + .collect(Collectors.toList()); + } + + private boolean partOfCurrentMovement(BlockPos pos) { + PathExecutor exec = baritone.getPathingBehavior().getCurrent(); + if (exec == null || exec.finished() || exec.failed()) { + return false; + } + Movement movement = (Movement) exec.getPath().movements().get(exec.getPosition()); + return Arrays.asList(movement.toBreakAll()).contains(pos); + } + + @Override + public void onLostControl() { + if (blocksToReplace != null && !blocksToReplace.isEmpty()) { + blocksToReplace.clear(); + } + } + + @Override + public String displayName0() { + return "Backfill"; + } + + @Override + public boolean isTemporary() { + return true; + } + + @Override + public double priority() { + return 5; + } +} diff --git a/src/main/java/baritone/process/BuilderProcess.java b/src/main/java/baritone/process/BuilderProcess.java index f4280269e..60322b925 100644 --- a/src/main/java/baritone/process/BuilderProcess.java +++ b/src/main/java/baritone/process/BuilderProcess.java @@ -35,9 +35,9 @@ import baritone.utils.BlockStateInterface; import baritone.utils.PathingCommandContext; import baritone.utils.schematic.AirSchematic; import baritone.utils.schematic.Schematic; +import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import net.minecraft.block.BlockAir; import net.minecraft.block.state.IBlockState; -import net.minecraft.client.Minecraft; import net.minecraft.init.Blocks; import net.minecraft.item.BlockItemUseContext; import net.minecraft.item.ItemBlock; @@ -61,6 +61,7 @@ import static baritone.api.pathing.movement.ActionCosts.COST_INF; public class BuilderProcess extends BaritoneProcessHelper implements IBuilderProcess { private HashSet incorrectPositions; + private LongOpenHashSet observedCompleted; // positions that are completed even if they're out of render distance and we can't make sure right now private String name; private ISchematic realSchematic; private ISchematic schematic; @@ -73,12 +74,6 @@ public class BuilderProcess extends BaritoneProcessHelper implements IBuilderPro super(baritone); } - public boolean build(String schematicFile, BlockPos origin) { - File file = new File(new File(Minecraft.getInstance().gameDir, "schematics"), schematicFile); - System.out.println(file + " " + file.exists()); - return build(schematicFile, file, origin); - } - @Override public void build(String name, ISchematic schematic, Vec3i origin) { this.name = name; @@ -87,12 +82,17 @@ public class BuilderProcess extends BaritoneProcessHelper implements IBuilderPro this.origin = origin; this.paused = false; this.layer = 0; + this.observedCompleted = new LongOpenHashSet(); } public void resume() { paused = false; } + public void pause() { + paused = true; + } + @Override public boolean build(String name, File schematic, Vec3i origin) { NBTTagCompound tag; @@ -140,15 +140,18 @@ public class BuilderProcess extends BaritoneProcessHelper implements IBuilderPro return state; } - - public Optional> toBreakNearPlayer(BuilderCalculationContext bcc) { + private Optional> toBreakNearPlayer(BuilderCalculationContext bcc) { BetterBlockPos center = ctx.playerFeet(); + BetterBlockPos pathStart = baritone.getPathingBehavior().pathStart(); for (int dx = -5; dx <= 5; dx++) { - for (int dy = 0; dy <= 5; dy++) { + for (int dy = Baritone.settings().breakFromAbove.value ? -1 : 0; dy <= 5; dy++) { for (int dz = -5; dz <= 5; dz++) { int x = center.x + dx; int y = center.y + dy; int z = center.z + dz; + if (dy == -1 && x == pathStart.x && z == pathStart.z) { + continue; // dont mine what we're supported by, but not directly standing on + } IBlockState desired = bcc.getSchematic(x, y, z); if (desired == null) { continue; // irrelevant @@ -181,7 +184,7 @@ public class BuilderProcess extends BaritoneProcessHelper implements IBuilderPro } } - public Optional searchForPlacables(BuilderCalculationContext bcc, List desirableOnHotbar) { + private Optional searchForPlacables(BuilderCalculationContext bcc, List desirableOnHotbar) { BetterBlockPos center = ctx.playerFeet(); for (int dx = -5; dx <= 5; dx++) { for (int dy = -5; dy <= 1; dy++) { @@ -215,7 +218,7 @@ public class BuilderProcess extends BaritoneProcessHelper implements IBuilderPro return voxelshape.isEmpty() || ctx.world().checkNoEntityCollision(null, voxelshape.withOffset(pos.getX(), pos.getY(), pos.getZ())); } - public Optional possibleToPlace(IBlockState toPlace, int x, int y, int z, BlockStateInterface bsi) { + private Optional possibleToPlace(IBlockState toPlace, int x, int y, int z, BlockStateInterface bsi) { for (EnumFacing against : EnumFacing.values()) { BetterBlockPos placeAgainstPos = new BetterBlockPos(x, y, z).offset(against); IBlockState placeAgainstState = bsi.get0(placeAgainstPos); @@ -246,8 +249,7 @@ public class BuilderProcess extends BaritoneProcessHelper implements IBuilderPro return Optional.empty(); } - - public OptionalInt hasAnyItemThatWouldPlace(IBlockState desired, RayTraceResult result, Rotation rot) { + private OptionalInt hasAnyItemThatWouldPlace(IBlockState desired, RayTraceResult result, Rotation rot) { for (int i = 0; i < 9; i++) { ItemStack stack = ctx.player().inventory.mainInventory.get(i); if (stack.isEmpty() || !(stack.getItem() instanceof ItemBlock)) { @@ -310,7 +312,7 @@ public class BuilderProcess extends BaritoneProcessHelper implements IBuilderPro } baritone.getInputOverrideHandler().clearAllKeys(); if (paused) { - return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE); + return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL); } if (Baritone.settings().buildInLayers.value) { if (realSchematic == null) { @@ -359,6 +361,7 @@ public class BuilderProcess extends BaritoneProcessHelper implements IBuilderPro layer = 0; origin = new BlockPos(origin).offset(direction, distance); logDirect("Repeating build " + distance + " blocks to the " + direction + ", new origin is " + origin); + return onTick(calcFailed, isSafeToCancel); } trim(bcc); @@ -376,10 +379,10 @@ public class BuilderProcess extends BaritoneProcessHelper implements IBuilderPro // and is unable since it's unsneaked in the intermediary tick baritone.getInputOverrideHandler().setInputForceState(Input.SNEAK, true); } - if (Objects.equals(ctx.objectMouseOver().getBlockPos(), pos) || ctx.playerRotations().isReallyCloseTo(rot)) { + if (ctx.isLookingAt(pos) || ctx.playerRotations().isReallyCloseTo(rot)) { baritone.getInputOverrideHandler().setInputForceState(Input.CLICK_LEFT, true); } - return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE); + return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL); } List desirableOnHotbar = new ArrayList<>(); Optional toPlace = searchForPlacables(bcc, desirableOnHotbar); @@ -388,10 +391,10 @@ public class BuilderProcess extends BaritoneProcessHelper implements IBuilderPro baritone.getLookBehavior().updateTarget(rot, true); ctx.player().inventory.currentItem = toPlace.get().hotbarSelection; baritone.getInputOverrideHandler().setInputForceState(Input.SNEAK, true); - if ((Objects.equals(ctx.objectMouseOver().getBlockPos(), toPlace.get().placeAgainst) && ctx.objectMouseOver().sideHit.equals(toPlace.get().side)) || ctx.playerRotations().isReallyCloseTo(rot)) { + if ((ctx.isLookingAt(toPlace.get().placeAgainst) && ctx.objectMouseOver().sideHit.equals(toPlace.get().side)) || ctx.playerRotations().isReallyCloseTo(rot)) { baritone.getInputOverrideHandler().setInputForceState(Input.CLICK_RIGHT, true); } - return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE); + return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL); } List approxPlacable = placable(36); @@ -433,7 +436,7 @@ public class BuilderProcess extends BaritoneProcessHelper implements IBuilderPro return new PathingCommandContext(goal, PathingCommandType.FORCE_REVALIDATE_GOAL_AND_PATH, bcc); } - public boolean recalc(BuilderCalculationContext bcc) { + private boolean recalc(BuilderCalculationContext bcc) { if (incorrectPositions == null) { incorrectPositions = new HashSet<>(); fullRecalc(bcc); @@ -448,7 +451,7 @@ public class BuilderProcess extends BaritoneProcessHelper implements IBuilderPro return !incorrectPositions.isEmpty(); } - public void trim(BuilderCalculationContext bcc) { + private void trim(BuilderCalculationContext bcc) { HashSet copy = new HashSet<>(incorrectPositions); copy.removeIf(pos -> pos.distanceSq(ctx.player().posX, ctx.player().posY, ctx.player().posZ) > 200); if (!copy.isEmpty()) { @@ -456,7 +459,7 @@ public class BuilderProcess extends BaritoneProcessHelper implements IBuilderPro } } - public void recalcNearby(BuilderCalculationContext bcc) { + private void recalcNearby(BuilderCalculationContext bcc) { BetterBlockPos center = ctx.playerFeet(); for (int dx = -5; dx <= 5; dx++) { for (int dy = -5; dy <= 5; dy++) { @@ -467,10 +470,13 @@ public class BuilderProcess extends BaritoneProcessHelper implements IBuilderPro IBlockState desired = bcc.getSchematic(x, y, z); if (desired != null) { // we care about this position + BetterBlockPos pos = new BetterBlockPos(x, y, z); if (valid(bcc.bsi.get0(x, y, z), desired)) { - incorrectPositions.remove(new BetterBlockPos(x, y, z)); + incorrectPositions.remove(pos); + observedCompleted.add(BetterBlockPos.longHash(pos)); } else { - incorrectPositions.add(new BetterBlockPos(x, y, z)); + incorrectPositions.add(pos); + observedCompleted.remove(BetterBlockPos.longHash(pos)); } } } @@ -478,13 +484,32 @@ public class BuilderProcess extends BaritoneProcessHelper implements IBuilderPro } } - public void fullRecalc(BuilderCalculationContext bcc) { + private void fullRecalc(BuilderCalculationContext bcc) { incorrectPositions = new HashSet<>(); for (int y = 0; y < schematic.heightY(); y++) { for (int z = 0; z < schematic.lengthZ(); z++) { for (int x = 0; x < schematic.widthX(); x++) { - if (schematic.inSchematic(x, y, z) && !valid(bcc.bsi.get0(x + origin.getX(), y + origin.getY(), z + origin.getZ()), schematic.desiredState(x, y, z))) { - incorrectPositions.add(new BetterBlockPos(x + origin.getX(), y + origin.getY(), z + origin.getZ())); + if (!schematic.inSchematic(x, y, z)) { + continue; + } + int blockX = x + origin.getX(); + int blockY = y + origin.getY(); + int blockZ = z + origin.getZ(); + if (bcc.bsi.worldContainsLoadedChunk(blockX, blockZ)) { // check if its in render distance, not if its in cache + // we can directly observe this block, it is in render distance + if (valid(bcc.bsi.get0(blockX, blockY, blockZ), schematic.desiredState(x, y, z))) { + observedCompleted.add(BetterBlockPos.longHash(blockX, blockY, blockZ)); + } else { + incorrectPositions.add(new BetterBlockPos(blockX, blockY, blockZ)); + observedCompleted.remove(BetterBlockPos.longHash(blockX, blockY, blockZ)); + } + continue; + } + // this is not in render distance + if (!observedCompleted.contains(BetterBlockPos.longHash(blockX, blockY, blockZ))) { + // and we've never seen this position be correct + // therefore mark as incorrect + incorrectPositions.add(new BetterBlockPos(blockX, blockY, blockZ)); } } } @@ -493,8 +518,8 @@ public class BuilderProcess extends BaritoneProcessHelper implements IBuilderPro private Goal assemble(BuilderCalculationContext bcc, List approxPlacable) { List placable = incorrectPositions.stream().filter(pos -> bcc.bsi.get0(pos).getBlock() instanceof BlockAir && approxPlacable.contains(bcc.getSchematic(pos.x, pos.y, pos.z))).collect(Collectors.toList()); - Goal[] toBreak = incorrectPositions.stream().filter(pos -> !(bcc.bsi.get0(pos).getBlock() instanceof BlockAir)).map(GoalBreak::new).toArray(Goal[]::new); - Goal[] toPlace = placable.stream().filter(pos -> !placable.contains(pos.down()) && !placable.contains(pos.down(2))).map(pos -> placementgoal(pos, bcc)).toArray(Goal[]::new); + Goal[] toBreak = incorrectPositions.stream().filter(pos -> !(bcc.bsi.get0(pos).getBlock() instanceof BlockAir)).map(pos -> breakGoal(pos, bcc)).toArray(Goal[]::new); + Goal[] toPlace = placable.stream().filter(pos -> !placable.contains(pos.down()) && !placable.contains(pos.down(2))).map(pos -> placementGoal(pos, bcc)).toArray(Goal[]::new); if (toPlace.length != 0) { return new JankyGoalComposite(new GoalComposite(toPlace), new GoalComposite(toBreak)); @@ -548,8 +573,8 @@ public class BuilderProcess extends BaritoneProcessHelper implements IBuilderPro } } - public Goal placementgoal(BlockPos pos, BuilderCalculationContext bcc) { - if (!(ctx.world().getBlockState(pos).getBlock() instanceof BlockAir)) { + private Goal placementGoal(BlockPos pos, BuilderCalculationContext bcc) { + if (!(ctx.world().getBlockState(pos).getBlock() instanceof BlockAir)) { // TODO can this even happen? return new GoalPlace(pos); } boolean allowSameLevel = !(ctx.world().getBlockState(pos.up()).getBlock() instanceof BlockAir); @@ -561,6 +586,21 @@ public class BuilderProcess extends BaritoneProcessHelper implements IBuilderPro return new GoalPlace(pos); } + private Goal breakGoal(BlockPos pos, BuilderCalculationContext bcc) { + if (Baritone.settings().goalBreakFromAbove.value && bcc.bsi.get0(pos.up()).getBlock() instanceof BlockAir && bcc.bsi.get0(pos.up(2)).getBlock() instanceof BlockAir) { // TODO maybe possible without the up(2) check? + return new JankyGoalComposite(new GoalBreak(pos), new GoalGetToBlock(pos.up()) { + @Override + public boolean isInGoal(int x, int y, int z) { + if (y > this.y || (x == this.x && y == this.y && z == this.z)) { + return false; + } + return super.isInGoal(x, y, z); + } + }); + } + return new GoalBreak(pos); + } + public static class GoalAdjacent extends GoalGetToBlock { private boolean allowSameLevel; @@ -607,6 +647,7 @@ public class BuilderProcess extends BaritoneProcessHelper implements IBuilderPro realSchematic = null; layer = 0; paused = false; + observedCompleted = null; } @Override @@ -614,7 +655,7 @@ public class BuilderProcess extends BaritoneProcessHelper implements IBuilderPro return paused ? "Builder Paused" : "Building " + name; } - public List placable(int size) { + private List placable(int size) { List result = new ArrayList<>(); for (int i = 0; i < size; i++) { ItemStack stack = ctx.player().inventory.mainInventory.get(i); @@ -629,7 +670,7 @@ public class BuilderProcess extends BaritoneProcessHelper implements IBuilderPro return result; } - public boolean valid(IBlockState current, IBlockState desired) { + private boolean valid(IBlockState current, IBlockState desired) { if (desired == null) { return true; } diff --git a/src/main/java/baritone/process/ExploreProcess.java b/src/main/java/baritone/process/ExploreProcess.java index eff4d2dee..35ddcb841 100644 --- a/src/main/java/baritone/process/ExploreProcess.java +++ b/src/main/java/baritone/process/ExploreProcess.java @@ -22,19 +22,33 @@ import baritone.api.cache.ICachedWorld; import baritone.api.pathing.goals.Goal; import baritone.api.pathing.goals.GoalComposite; import baritone.api.pathing.goals.GoalXZ; +import baritone.api.pathing.goals.GoalYLevel; +import baritone.api.process.IExploreProcess; import baritone.api.process.PathingCommand; import baritone.api.process.PathingCommandType; +import baritone.api.utils.MyChunkPos; import baritone.cache.CachedWorld; import baritone.utils.BaritoneProcessHelper; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import java.io.InputStreamReader; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; import java.util.List; -public class ExploreProcess extends BaritoneProcessHelper { +public class ExploreProcess extends BaritoneProcessHelper implements IExploreProcess { private BlockPos explorationOrigin; + private IChunkFilter filter; + + private int distanceCompleted; + public ExploreProcess(Baritone baritone) { super(baritone); } @@ -44,8 +58,25 @@ public class ExploreProcess extends BaritoneProcessHelper { return explorationOrigin != null; } + @Override public void explore(int centerX, int centerZ) { explorationOrigin = new BlockPos(centerX, 0, centerZ); + distanceCompleted = 0; + } + + @Override + public void applyJsonFilter(Path path, boolean invert) throws Exception { + filter = new JsonChunkFilter(path, invert); + } + + public IChunkFilter calcFilter() { + IChunkFilter filter; + if (this.filter != null) { + filter = new EitherChunk(this.filter, new BaritoneChunkCache()); + } else { + filter = new BaritoneChunkCache(); + } + return filter; } @Override @@ -55,45 +86,192 @@ public class ExploreProcess extends BaritoneProcessHelper { onLostControl(); return null; } - Goal[] closestUncached = closestUncachedChunks(explorationOrigin); + IChunkFilter filter = calcFilter(); + if (!Baritone.settings().disableCompletionCheck.value && filter.countRemain() == 0) { + logDirect("Explored all chunks"); + onLostControl(); + return null; + } + Goal[] closestUncached = closestUncachedChunks(explorationOrigin, filter); if (closestUncached == null) { logDebug("awaiting region load from disk"); return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE); } - System.out.println("Closest uncached: " + closestUncached); return new PathingCommand(new GoalComposite(closestUncached), PathingCommandType.FORCE_REVALIDATE_GOAL_AND_PATH); } - private Goal[] closestUncachedChunks(BlockPos center) { + private Goal[] closestUncachedChunks(BlockPos center, IChunkFilter filter) { int chunkX = center.getX() >> 4; int chunkZ = center.getZ() >> 4; - ICachedWorld cache = baritone.getWorldProvider().getCurrentWorld().getCachedWorld(); - for (int dist = 0; ; dist++) { - List centers = new ArrayList<>(); + int count = Math.min(filter.countRemain(), Baritone.settings().exploreChunkSetMinimumSize.value); + List centers = new ArrayList<>(); + int renderDistance = Baritone.settings().worldExploringChunkOffset.value; + for (int dist = distanceCompleted; ; dist++) { for (int dx = -dist; dx <= dist; dx++) { - for (int dz = -dist; dz <= dist; dz++) { - int trueDist = Baritone.settings().exploreUsePythagorean.value ? dx * dx + dz * dz : Math.abs(dx) + Math.abs(dz); + int zval = dist - Math.abs(dx); + for (int mult = 0; mult < 2; mult++) { + int dz = (mult * 2 - 1) * zval; // dz can be either -zval or zval + int trueDist = Math.abs(dx) + Math.abs(dz); if (trueDist != dist) { - continue; // not considering this one just yet in our expanding search + throw new IllegalStateException(); } - int centerX = (chunkX + dx) * 16 + 8; - int centerZ = (chunkZ + dz) * 18 + 8; - - if (cache.isCached(centerX, centerZ)) { - continue; + switch (filter.isAlreadyExplored(chunkX + dx, chunkZ + dz)) { + case UNKNOWN: + return null; // awaiting load + case NOT_EXPLORED: + break; // note: this breaks the switch not the for + case EXPLORED: + continue; // note: this continues the for } - if (!((CachedWorld) cache).regionLoaded(centerX, centerZ)) { - Baritone.getExecutor().execute(() -> { - ((CachedWorld) cache).tryLoadFromDisk(centerX >> 9, centerZ >> 9); - }); - return null; // we still need to load regions from disk in order to decide properly + int centerX = ((chunkX + dx) << 4) + 8; + int centerZ = ((chunkZ + dz) << 4) + 8; + int offset = renderDistance << 4; + if (dx < 0) { + centerX -= offset; + } else { + centerX += offset; + } + if (dz < 0) { + centerZ -= offset; + } else { + centerZ += offset; } centers.add(new BlockPos(centerX, 0, centerZ)); } } - if (!centers.isEmpty()) { - return centers.stream().map(pos -> new GoalXZ(pos.getX(), pos.getZ())).toArray(Goal[]::new); + if (centers.size() >= count) { + return centers.stream().map(pos -> createGoal(pos.getX(), pos.getZ())).toArray(Goal[]::new); } + if (centers.isEmpty()) { + // we have explored everything from 0 to dist inclusive + // next time we should start our check at dist+1 + distanceCompleted = dist + 1; + } + } + } + + private static Goal createGoal(int x, int z) { + if (Baritone.settings().exploreMaintainY.value == -1) { + return new GoalXZ(x, z); + } + // don't use a goalblock because we still want isInGoal to return true if X and Z are correct + // we just want to try and maintain Y on the way there, not necessarily end at that specific Y + return new GoalXZ(x, z) { + @Override + public double heuristic(int x, int y, int z) { + return super.heuristic(x, y, z) + GoalYLevel.calculate(Baritone.settings().exploreMaintainY.value, y); + } + }; + } + + private enum Status { + EXPLORED, NOT_EXPLORED, UNKNOWN; + } + + private interface IChunkFilter { + Status isAlreadyExplored(int chunkX, int chunkZ); + + int countRemain(); + } + + private class BaritoneChunkCache implements IChunkFilter { + + private final ICachedWorld cache = baritone.getWorldProvider().getCurrentWorld().getCachedWorld(); + + @Override + public Status isAlreadyExplored(int chunkX, int chunkZ) { + int centerX = chunkX << 4; + int centerZ = chunkZ << 4; + if (cache.isCached(centerX, centerZ)) { + return Status.EXPLORED; + } + if (!((CachedWorld) cache).regionLoaded(centerX, centerZ)) { + Baritone.getExecutor().execute(() -> { + ((CachedWorld) cache).tryLoadFromDisk(centerX >> 9, centerZ >> 9); + }); + return Status.UNKNOWN; // we still need to load regions from disk in order to decide properly + } + return Status.NOT_EXPLORED; + } + + @Override + public int countRemain() { + return Integer.MAX_VALUE; + } + } + + private class JsonChunkFilter implements IChunkFilter { + private final boolean invert; // if true, the list is interpreted as a list of chunks that are NOT explored, if false, the list is interpreted as a list of chunks that ARE explored + private final LongOpenHashSet inFilter; + private final MyChunkPos[] positions; + + private JsonChunkFilter(Path path, boolean invert) throws Exception { // ioexception, json exception, etc + this.invert = invert; + Gson gson = new GsonBuilder().create(); + positions = gson.fromJson(new InputStreamReader(Files.newInputStream(path)), MyChunkPos[].class); + logDirect("Loaded " + positions.length + " positions"); + inFilter = new LongOpenHashSet(); + for (MyChunkPos mcp : positions) { + inFilter.add(ChunkPos.asLong(mcp.x, mcp.z)); + } + } + + @Override + public Status isAlreadyExplored(int chunkX, int chunkZ) { + if (inFilter.contains(ChunkPos.asLong(chunkX, chunkZ)) ^ invert) { + // either it's on the list of explored chunks, or it's not on the list of unexplored chunks + // either way, we have it + return Status.EXPLORED; + } else { + // either it's not on the list of explored chunks, or it's on the list of unexplored chunks + // either way, it depends on if baritone has cached it so defer to that + return Status.UNKNOWN; + } + } + + @Override + public int countRemain() { + if (!invert) { + // if invert is false, anything not on the list is uncached + return Integer.MAX_VALUE; + } + // but if invert is true, anything not on the list IS assumed cached + // so we are done if everything on our list is cached! + int countRemain = 0; + BaritoneChunkCache bcc = new BaritoneChunkCache(); + for (MyChunkPos pos : positions) { + if (bcc.isAlreadyExplored(pos.x, pos.z) != Status.EXPLORED) { + // either waiting for it or dont have it at all + countRemain++; + if (countRemain >= Baritone.settings().exploreChunkSetMinimumSize.value) { + return countRemain; + } + } + } + return countRemain; + } + } + + private class EitherChunk implements IChunkFilter { + private final IChunkFilter a; + private final IChunkFilter b; + + private EitherChunk(IChunkFilter a, IChunkFilter b) { + this.a = a; + this.b = b; + } + + @Override + public Status isAlreadyExplored(int chunkX, int chunkZ) { + if (a.isAlreadyExplored(chunkX, chunkZ) == Status.EXPLORED) { + return Status.EXPLORED; + } + return b.isAlreadyExplored(chunkX, chunkZ); + } + + @Override + public int countRemain() { + return Math.min(a.countRemain(), b.countRemain()); } } @@ -104,6 +282,6 @@ public class ExploreProcess extends BaritoneProcessHelper { @Override public String displayName0() { - return "Exploring around " + explorationOrigin + ", currently going to " + new GoalComposite(closestUncachedChunks(explorationOrigin)); + return "Exploring around " + explorationOrigin + ", distance completed " + distanceCompleted + ", currently going to " + new GoalComposite(closestUncachedChunks(explorationOrigin, calcFilter())); } } diff --git a/src/main/java/baritone/process/FarmProcess.java b/src/main/java/baritone/process/FarmProcess.java new file mode 100644 index 000000000..c688fbbed --- /dev/null +++ b/src/main/java/baritone/process/FarmProcess.java @@ -0,0 +1,281 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package baritone.process; + +import baritone.Baritone; +import baritone.api.pathing.goals.Goal; +import baritone.api.pathing.goals.GoalBlock; +import baritone.api.pathing.goals.GoalComposite; +import baritone.api.process.IFarmProcess; +import baritone.api.process.PathingCommand; +import baritone.api.process.PathingCommandType; +import baritone.api.utils.Rotation; +import baritone.api.utils.RotationUtils; +import baritone.api.utils.input.Input; +import baritone.cache.WorldScanner; +import baritone.pathing.movement.MovementHelper; +import baritone.utils.BaritoneProcessHelper; +import net.minecraft.block.*; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.Entity; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.function.Predicate; + +public class FarmProcess extends BaritoneProcessHelper implements IFarmProcess { + + private boolean active; + + private static final List FARMLAND_PLANTABLE = Arrays.asList( + Items.BEETROOT_SEEDS, + Items.MELON_SEEDS, + Items.WHEAT_SEEDS, + Items.PUMPKIN_SEEDS, + Items.POTATO, + Items.CARROT + ); + + private static final List PICKUP_DROPPED = Arrays.asList( + Items.BEETROOT_SEEDS, + Items.WHEAT, + Items.MELON_SEEDS, + Items.MELON_SLICE, + Items.WHEAT_SEEDS, + Items.WHEAT, + Items.PUMPKIN_SEEDS, + Items.POTATO, + Items.CARROT, + Items.BEETROOT, + Blocks.PUMPKIN.asItem(), + Blocks.MELON.asItem(), + Items.NETHER_WART, + Blocks.SUGAR_CANE.asItem(), + Blocks.CACTUS.asItem() + ); + + public FarmProcess(Baritone baritone) { + super(baritone); + } + + @Override + public boolean isActive() { + return active; + } + + @Override + public void farm() { + active = true; + } + + private enum Harvest { + WHEAT((BlockCrops) Blocks.WHEAT), + CARROTS((BlockCrops) Blocks.CARROTS), + POTATOES((BlockCrops) Blocks.POTATOES), + BEETROOT((BlockCrops) Blocks.BEETROOTS), + PUMPKIN(Blocks.PUMPKIN, state -> true), + MELON(Blocks.MELON, state -> true), + NETHERWART(Blocks.NETHER_WART, state -> state.get(BlockNetherWart.AGE) >= 3), + SUGARCANE(Blocks.SUGAR_CANE, null) { + @Override + public boolean readyToHarvest(World world, BlockPos pos, IBlockState state) { + return world.getBlockState(pos.down()).getBlock() instanceof BlockReed; + } + }, + CACTUS(Blocks.CACTUS, null) { + @Override + public boolean readyToHarvest(World world, BlockPos pos, IBlockState state) { + return world.getBlockState(pos.down()).getBlock() instanceof BlockCactus; + } + }; + public final Block block; + public final Predicate readyToHarvest; + + Harvest(BlockCrops blockCrops) { + this(blockCrops, blockCrops::isMaxAge); + // max age is 7 for wheat, carrots, and potatoes, but 3 for beetroot + } + + Harvest(Block block, Predicate readyToHarvest) { + this.block = block; + this.readyToHarvest = readyToHarvest; + } + + public boolean readyToHarvest(World world, BlockPos pos, IBlockState state) { + return readyToHarvest.test(state); + } + } + + private boolean readyForHarvest(World world, BlockPos pos, IBlockState state) { + for (Harvest harvest : Harvest.values()) { + if (harvest.block == state.getBlock()) { + return harvest.readyToHarvest(world, pos, state); + } + } + return false; + } + + private boolean isPlantable(ItemStack stack) { + return FARMLAND_PLANTABLE.contains(stack.getItem()); + } + + private boolean isBoneMeal(ItemStack stack) { + return !stack.isEmpty() && stack.getItem().equals(Items.BONE_MEAL); + } + + private boolean isNetherWart(ItemStack stack) { + return !stack.isEmpty() && stack.getItem().equals(Items.NETHER_WART); + } + + @Override + public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) { + ArrayList scan = new ArrayList<>(); + for (Harvest harvest : Harvest.values()) { + scan.add(harvest.block); + } + scan.add(Blocks.FARMLAND); + if (Baritone.settings().replantNetherWart.value) { + scan.add(Blocks.SOUL_SAND); + } + + List locations = WorldScanner.INSTANCE.scanChunkRadius(ctx, scan, 256, 10, 4); + + List toBreak = new ArrayList<>(); + List openFarmland = new ArrayList<>(); + List bonemealable = new ArrayList<>(); + List openSoulsand = new ArrayList<>(); + for (BlockPos pos : locations) { + IBlockState state = ctx.world().getBlockState(pos); + boolean airAbove = ctx.world().getBlockState(pos.up()).getBlock() instanceof BlockAir; + if (state.getBlock() == Blocks.FARMLAND) { + if (airAbove) { + openFarmland.add(pos); + } + continue; + } + if (state.getBlock() == Blocks.SOUL_SAND) { + if (airAbove) { + openSoulsand.add(pos); + } + continue; + } + if (readyForHarvest(ctx.world(), pos, state)) { + toBreak.add(pos); + continue; + } + if (state.getBlock() instanceof IGrowable) { + IGrowable ig = (IGrowable) state.getBlock(); + if (ig.canGrow(ctx.world(), pos, state, true) && ig.canUseBonemeal(ctx.world(), ctx.world().rand, pos, state)) { + bonemealable.add(pos); + } + } + } + + baritone.getInputOverrideHandler().clearAllKeys(); + for (BlockPos pos : toBreak) { + Optional rot = RotationUtils.reachable(ctx, pos); + if (rot.isPresent() && isSafeToCancel) { + baritone.getLookBehavior().updateTarget(rot.get(), true); + MovementHelper.switchToBestToolFor(ctx, ctx.world().getBlockState(pos)); + if (ctx.isLookingAt(pos)) { + baritone.getInputOverrideHandler().setInputForceState(Input.CLICK_LEFT, true); + } + return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE); + } + } + ArrayList both = new ArrayList<>(openFarmland); + both.addAll(openSoulsand); + for (BlockPos pos : both) { + boolean soulsand = openSoulsand.contains(pos); + Optional rot = RotationUtils.reachableOffset(ctx.player(), pos, new Vec3d(pos.getX() + 0.5, pos.getY() + 1, pos.getZ() + 0.5), ctx.playerController().getBlockReachDistance()); + if (rot.isPresent() && isSafeToCancel && baritone.getInventoryBehavior().throwaway(true, soulsand ? this::isNetherWart : this::isPlantable)) { + baritone.getLookBehavior().updateTarget(rot.get(), true); + if (ctx.isLookingAt(pos)) { + baritone.getInputOverrideHandler().setInputForceState(Input.CLICK_RIGHT, true); + } + return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE); + } + } + for (BlockPos pos : bonemealable) { + Optional rot = RotationUtils.reachable(ctx, pos); + if (rot.isPresent() && isSafeToCancel && baritone.getInventoryBehavior().throwaway(true, this::isBoneMeal)) { + baritone.getLookBehavior().updateTarget(rot.get(), true); + if (ctx.isLookingAt(pos)) { + baritone.getInputOverrideHandler().setInputForceState(Input.CLICK_RIGHT, true); + } + return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE); + } + } + + if (calcFailed) { + logDirect("Farm failed"); + onLostControl(); + return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE); + } + + List goalz = new ArrayList<>(); + for (BlockPos pos : toBreak) { + goalz.add(new BuilderProcess.GoalBreak(pos)); + } + if (baritone.getInventoryBehavior().throwaway(false, this::isPlantable)) { + for (BlockPos pos : openFarmland) { + goalz.add(new GoalBlock(pos.up())); + } + } + if (baritone.getInventoryBehavior().throwaway(false, this::isNetherWart)) { + for (BlockPos pos : openSoulsand) { + goalz.add(new GoalBlock(pos.up())); + } + } + if (baritone.getInventoryBehavior().throwaway(false, this::isBoneMeal)) { + for (BlockPos pos : bonemealable) { + goalz.add(new GoalBlock(pos)); + } + } + for (Entity entity : ctx.world().loadedEntityList) { + if (entity instanceof EntityItem && entity.onGround) { + EntityItem ei = (EntityItem) entity; + if (PICKUP_DROPPED.contains(ei.getItem().getItem())) { + // +0.1 because of farmland's 0.9375 dummy height lol + goalz.add(new GoalBlock(new BlockPos(entity.posX, entity.posY + 0.1, entity.posZ))); + } + } + } + return new PathingCommand(new GoalComposite(goalz.toArray(new Goal[0])), PathingCommandType.SET_GOAL_AND_PATH); + } + + @Override + public void onLostControl() { + active = false; + } + + @Override + public String displayName0() { + return "Farming"; + } +} diff --git a/src/main/java/baritone/process/GetToBlockProcess.java b/src/main/java/baritone/process/GetToBlockProcess.java index 5664bebba..292e4c6d0 100644 --- a/src/main/java/baritone/process/GetToBlockProcess.java +++ b/src/main/java/baritone/process/GetToBlockProcess.java @@ -42,6 +42,7 @@ public class GetToBlockProcess extends BaritoneProcessHelper implements IGetToBl private BlockPos start; private int tickCount = 0; + private int arrivalTickCount = 0; public GetToBlockProcess(Baritone baritone) { super(baritone); @@ -53,6 +54,7 @@ public class GetToBlockProcess extends BaritoneProcessHelper implements IGetToBl gettingTo = block; start = ctx.playerFeet(); blacklist = new ArrayList<>(); + arrivalTickCount = 0; rescan(new ArrayList<>(), new CalculationContext(baritone)); } @@ -117,7 +119,7 @@ public class GetToBlockProcess extends BaritoneProcessHelper implements IGetToBl } // blacklist the closest block and its adjacent blocks - public synchronized void blacklistClosest() { + public synchronized boolean blacklistClosest() { List newBlacklist = new ArrayList<>(); knownLocations.stream().min(Comparator.comparingDouble(ctx.player()::getDistanceSq)).ifPresent(newBlacklist::add); outer: @@ -140,6 +142,7 @@ public class GetToBlockProcess extends BaritoneProcessHelper implements IGetToBl } logDebug("Blacklisting unreachable locations " + newBlacklist); blacklist.addAll(newBlacklist); + return !newBlacklist.isEmpty(); } // safer than direct double comparison from distanceSq @@ -195,6 +198,10 @@ public class GetToBlockProcess extends BaritoneProcessHelper implements IGetToBl return true; } } + if (arrivalTickCount++ > 20) { + logDirect("Right click timed out"); + return true; + } return false; // trying to right click, will do it next tick or so } } diff --git a/src/main/java/baritone/process/MineProcess.java b/src/main/java/baritone/process/MineProcess.java index 3444a3949..fda9a33a3 100644 --- a/src/main/java/baritone/process/MineProcess.java +++ b/src/main/java/baritone/process/MineProcess.java @@ -22,10 +22,12 @@ import baritone.api.pathing.goals.*; import baritone.api.process.IMineProcess; import baritone.api.process.PathingCommand; import baritone.api.process.PathingCommandType; +import baritone.api.utils.BlockUtils; import baritone.api.utils.IPlayerContext; +import baritone.api.utils.Rotation; import baritone.api.utils.RotationUtils; +import baritone.api.utils.input.Input; import baritone.cache.CachedChunk; -import baritone.cache.ChunkPacker; import baritone.cache.WorldScanner; import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.MovementHelper; @@ -33,6 +35,8 @@ import baritone.utils.BaritoneProcessHelper; import baritone.utils.BlockStateInterface; import net.minecraft.block.Block; import net.minecraft.block.BlockAir; +import net.minecraft.block.BlockFalling; +import net.minecraft.block.state.IBlockState; import net.minecraft.entity.Entity; import net.minecraft.entity.item.EntityItem; import net.minecraft.init.Blocks; @@ -44,6 +48,8 @@ import net.minecraft.world.World; import java.util.*; import java.util.stream.Collectors; +import static baritone.api.pathing.movement.ActionCosts.COST_INF; + /** * Mine blocks of a certain type * @@ -95,14 +101,35 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro return null; } int mineGoalUpdateInterval = Baritone.settings().mineGoalUpdateInterval.value; + List curr = new ArrayList<>(knownOreLocations); if (mineGoalUpdateInterval != 0 && tickCount++ % mineGoalUpdateInterval == 0) { // big brain - List curr = new ArrayList<>(knownOreLocations); CalculationContext context = new CalculationContext(baritone, true); Baritone.getExecutor().execute(() -> rescan(curr, context)); } if (Baritone.settings().legitMine.value) { addNearby(); } + Optional shaft = curr.stream() + .filter(pos -> pos.getX() == ctx.playerFeet().getX() && pos.getZ() == ctx.playerFeet().getZ()) + .filter(pos -> pos.getY() >= ctx.playerFeet().getY()) + .filter(pos -> !(BlockStateInterface.get(ctx, pos).getBlock() instanceof BlockAir)) // after breaking a block, it takes mineGoalUpdateInterval ticks for it to actually update this list =( + .min(Comparator.comparingDouble(ctx.player()::getDistanceSq)); + baritone.getInputOverrideHandler().clearAllKeys(); + if (shaft.isPresent()) { + BlockPos pos = shaft.get(); + IBlockState state = baritone.bsi.get0(pos); + if (!MovementHelper.avoidBreaking(baritone.bsi, pos.getX(), pos.getY(), pos.getZ(), state)) { + Optional rot = RotationUtils.reachable(ctx, pos); + if (rot.isPresent() && isSafeToCancel) { + baritone.getLookBehavior().updateTarget(rot.get(), true); + MovementHelper.switchToBestToolFor(ctx, ctx.world().getBlockState(pos)); + if (ctx.isLookingAt(pos) || ctx.playerRotations().isReallyCloseTo(rot.get())) { + baritone.getInputOverrideHandler().setInputForceState(Input.CLICK_LEFT, true); + } + return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE); + } + } + } PathingCommand command = updateGoal(); if (command == null) { // none in range @@ -129,7 +156,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro if (!locs.isEmpty()) { List locs2 = prune(new CalculationContext(baritone), new ArrayList<>(locs), mining, ORE_LOCATIONS_COUNT, blacklist); // can't reassign locs, gotta make a new var locs2, because we use it in a lambda right here, and variables you use in a lambda must be effectively final - Goal goal = new GoalComposite(locs2.stream().map(loc -> coalesce(ctx, loc, locs2)).toArray(Goal[]::new)); + Goal goal = new GoalComposite(locs2.stream().map(loc -> coalesce(loc, locs2)).toArray(Goal[]::new)); knownOreLocations = locs2; return new PathingCommand(goal, legit ? PathingCommandType.FORCE_REVALIDATE_GOAL_AND_PATH : PathingCommandType.REVALIDATE_GOAL_AND_PATH); } @@ -179,15 +206,71 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro knownOreLocations = locs; } - private static Goal coalesce(IPlayerContext ctx, BlockPos loc, List locs) { + private static boolean internalMiningGoal(BlockPos pos, IPlayerContext ctx, List locs) { + // Here, BlockStateInterface is used because the position may be in a cached chunk (the targeted block is one that is kept track of) + return locs.contains(pos) || (Baritone.settings().internalMiningAirException.value && BlockStateInterface.getBlock(ctx, pos) instanceof BlockAir); + } + + private Goal coalesce(BlockPos loc, List locs) { + boolean assumeVerticalShaftMine = !(baritone.bsi.get0(loc.up()).getBlock() instanceof BlockFalling); if (!Baritone.settings().forceInternalMining.value) { - return new GoalTwoBlocks(loc); + if (assumeVerticalShaftMine) { + // we can get directly below the block + return new GoalThreeBlocks(loc); + } else { + // we need to get feet or head into the block + return new GoalTwoBlocks(loc); + } + } + boolean upwardGoal = internalMiningGoal(loc.up(), ctx, locs); + boolean downwardGoal = internalMiningGoal(loc.down(), ctx, locs); + boolean doubleDownwardGoal = internalMiningGoal(loc.down(2), ctx, locs); + if (upwardGoal == downwardGoal) { // symmetric + if (doubleDownwardGoal && assumeVerticalShaftMine) { + // we have a checkerboard like pattern + // this one, and the one two below it + // therefore it's fine to path to immediately below this one, since your feet will be in the doubleDownwardGoal + // but only if assumeVerticalShaftMine + return new GoalThreeBlocks(loc); + } else { + // this block has nothing interesting two below, but is symmetric vertically so we can get either feet or head into it + return new GoalTwoBlocks(loc); + } + } + if (upwardGoal) { + // downwardGoal known to be false + // ignore the gap then potential doubleDownward, because we want to path feet into this one and head into upwardGoal + return new GoalBlock(loc); + } + // upwardGoal known to be false, downwardGoal known to be true + if (doubleDownwardGoal && assumeVerticalShaftMine) { + // this block and two below it are goals + // path into the center of the one below, because that includes directly below this one + return new GoalTwoBlocks(loc.down()); + } + // upwardGoal false, downwardGoal true, doubleDownwardGoal false + // just this block and the one immediately below, no others + return new GoalBlock(loc.down()); + } + + private static class GoalThreeBlocks extends GoalTwoBlocks { + + public GoalThreeBlocks(BlockPos pos) { + super(pos); } - // Here, BlockStateInterface is used because the position may be in a cached chunk (the targeted block is one that is kept track of) - boolean upwardGoal = locs.contains(loc.up()) || (Baritone.settings().internalMiningAirException.value && BlockStateInterface.getBlock(ctx, loc.up()) instanceof BlockAir); - boolean downwardGoal = locs.contains(loc.down()) || (Baritone.settings().internalMiningAirException.value && BlockStateInterface.getBlock(ctx, loc.down()) instanceof BlockAir); - return upwardGoal == downwardGoal ? new GoalTwoBlocks(loc) : upwardGoal ? new GoalBlock(loc) : new GoalBlock(loc.down()); + @Override + public boolean isInGoal(int x, int y, int z) { + return x == this.x && (y == this.y || y == this.y - 1 || y == this.y - 2) && z == this.z; + } + + @Override + public double heuristic(int x, int y, int z) { + int xDiff = x - this.x; + int yDiff = y - this.y; + int zDiff = z - this.z; + return GoalBlock.calculate(xDiff, yDiff < -1 ? yDiff + 2 : yDiff == -1 ? 0 : yDiff, zDiff); + } } public static List droppedItemsScan(List mining, World world) { @@ -216,24 +299,20 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro public static List searchWorld(CalculationContext ctx, List mining, int max, List alreadyKnown, List blacklist) { List locs = new ArrayList<>(); List uninteresting = new ArrayList<>(); - //long b = System.currentTimeMillis(); for (Block m : mining) { if (CachedChunk.BLOCKS_TO_KEEP_TRACK_OF.contains(m)) { // maxRegionDistanceSq 2 means adjacent directly or adjacent diagonally; nothing further than that - locs.addAll(ctx.worldData.getCachedWorld().getLocationsOf(ChunkPacker.blockToString(m), Baritone.settings().maxCachedWorldScanCount.value, ctx.getBaritone().getPlayerContext().playerFeet().getX(), ctx.getBaritone().getPlayerContext().playerFeet().getZ(), 2)); + locs.addAll(ctx.worldData.getCachedWorld().getLocationsOf(BlockUtils.blockToString(m), Baritone.settings().maxCachedWorldScanCount.value, ctx.getBaritone().getPlayerContext().playerFeet().getX(), ctx.getBaritone().getPlayerContext().playerFeet().getZ(), 2)); } else { uninteresting.add(m); } } locs = prune(ctx, locs, mining, max, blacklist); - //System.out.println("Scan of cached chunks took " + (System.currentTimeMillis() - b) + "ms"); - if (locs.isEmpty()) { + if (locs.isEmpty() || (Baritone.settings().extendCacheOnThreshold.value && locs.size() < max)) { uninteresting = mining; } if (!uninteresting.isEmpty()) { - //long before = System.currentTimeMillis(); locs.addAll(WorldScanner.INSTANCE.scanChunkRadius(ctx.getBaritone().getPlayerContext(), uninteresting, max, 10, 32)); // maxSearchRadius is NOT sq - //System.out.println("Scan of loaded chunks took " + (System.currentTimeMillis() - before) + "ms"); } locs.addAll(alreadyKnown); return prune(ctx, locs, mining, max, blacklist); @@ -266,7 +345,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro List dropped = droppedItemsScan(mining, ctx.world); dropped.removeIf(drop -> { for (BlockPos pos : locs2) { - if (pos.distanceSq(drop) <= 9 && mining.contains(ctx.getBlock(pos.getX(), pos.getY(), pos.getZ())) && MineProcess.plausibleToBreak(ctx.bsi, pos)) { // TODO maybe drop also has to be supported? no lava below? + if (pos.distanceSq(drop) <= 9 && mining.contains(ctx.getBlock(pos.getX(), pos.getY(), pos.getZ())) && MineProcess.plausibleToBreak(ctx, pos)) { // TODO maybe drop also has to be supported? no lava below? return true; } } @@ -280,7 +359,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro .filter(pos -> !ctx.bsi.worldContainsLoadedChunk(pos.getX(), pos.getZ()) || mining.contains(ctx.getBlock(pos.getX(), pos.getY(), pos.getZ())) || dropped.contains(pos)) // remove any that are implausible to mine (encased in bedrock, or touching lava) - .filter(pos -> MineProcess.plausibleToBreak(ctx.bsi, pos)) + .filter(pos -> MineProcess.plausibleToBreak(ctx, pos)) .filter(pos -> !blacklist.contains(pos)) @@ -293,18 +372,18 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro return locs; } - public static boolean plausibleToBreak(BlockStateInterface bsi, BlockPos pos) { - if (MovementHelper.avoidBreaking(bsi, pos.getX(), pos.getY(), pos.getZ(), bsi.get0(pos))) { + public static boolean plausibleToBreak(CalculationContext ctx, BlockPos pos) { + if (MovementHelper.getMiningDurationTicks(ctx, pos.getX(), pos.getY(), pos.getZ(), ctx.bsi.get0(pos), true) >= COST_INF) { return false; } // bedrock above and below makes it implausible, otherwise we're good - return !(bsi.get0(pos.up()).getBlock() == Blocks.BEDROCK && bsi.get0(pos.down()).getBlock() == Blocks.BEDROCK); + return !(ctx.bsi.get0(pos.up()).getBlock() == Blocks.BEDROCK && ctx.bsi.get0(pos.down()).getBlock() == Blocks.BEDROCK); } @Override public void mineByName(int quantity, String... blocks) { - mine(quantity, blocks == null || blocks.length == 0 ? null : Arrays.stream(blocks).map(ChunkPacker::stringToBlockRequired).toArray(Block[]::new)); + mine(quantity, blocks == null || blocks.length == 0 ? null : Arrays.stream(blocks).map(BlockUtils::stringToBlockRequired).toArray(Block[]::new)); } @Override diff --git a/src/main/java/baritone/utils/BaritoneAutoTest.java b/src/main/java/baritone/utils/BaritoneAutoTest.java index 1629aa8c7..c55289f1d 100644 --- a/src/main/java/baritone/utils/BaritoneAutoTest.java +++ b/src/main/java/baritone/utils/BaritoneAutoTest.java @@ -22,6 +22,7 @@ import baritone.api.event.events.TickEvent; import baritone.api.event.listener.AbstractGameEventListener; import baritone.api.pathing.goals.Goal; import baritone.api.pathing.goals.GoalBlock; +import baritone.api.utils.Helper; import baritone.api.utils.IPlayerContext; import net.minecraft.client.GameSettings; import net.minecraft.client.Minecraft; diff --git a/src/main/java/baritone/utils/BaritoneProcessHelper.java b/src/main/java/baritone/utils/BaritoneProcessHelper.java index 61c2fd448..6abec9493 100644 --- a/src/main/java/baritone/utils/BaritoneProcessHelper.java +++ b/src/main/java/baritone/utils/BaritoneProcessHelper.java @@ -19,6 +19,7 @@ package baritone.utils; import baritone.Baritone; import baritone.api.process.IBaritoneProcess; +import baritone.api.utils.Helper; import baritone.api.utils.IPlayerContext; public abstract class BaritoneProcessHelper implements IBaritoneProcess, Helper { diff --git a/src/main/java/baritone/utils/BlockBreakHelper.java b/src/main/java/baritone/utils/BlockBreakHelper.java index b5b7c7757..4b2dcfc65 100644 --- a/src/main/java/baritone/utils/BlockBreakHelper.java +++ b/src/main/java/baritone/utils/BlockBreakHelper.java @@ -17,6 +17,7 @@ package baritone.utils; +import baritone.api.utils.Helper; import baritone.api.utils.IPlayerContext; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; diff --git a/src/main/java/baritone/utils/BlockPlaceHelper.java b/src/main/java/baritone/utils/BlockPlaceHelper.java index 124ffa711..1ffb0e1fc 100644 --- a/src/main/java/baritone/utils/BlockPlaceHelper.java +++ b/src/main/java/baritone/utils/BlockPlaceHelper.java @@ -18,6 +18,7 @@ package baritone.utils; import baritone.Baritone; +import baritone.api.utils.Helper; import baritone.api.utils.IPlayerContext; import net.minecraft.util.EnumActionResult; import net.minecraft.util.EnumHand; diff --git a/src/main/java/baritone/utils/PathRenderer.java b/src/main/java/baritone/utils/PathRenderer.java index 60f9838f1..98ad3f9b9 100644 --- a/src/main/java/baritone/utils/PathRenderer.java +++ b/src/main/java/baritone/utils/PathRenderer.java @@ -23,6 +23,7 @@ import baritone.api.event.events.RenderEvent; import baritone.api.pathing.calc.IPath; import baritone.api.pathing.goals.*; import baritone.api.utils.BetterBlockPos; +import baritone.api.utils.Helper; import baritone.api.utils.interfaces.IGoalRenderPos; import baritone.behavior.PathingBehavior; import baritone.pathing.path.PathExecutor; diff --git a/src/main/java/baritone/utils/PathingControlManager.java b/src/main/java/baritone/utils/PathingControlManager.java index f6a6954d2..92b66c491 100644 --- a/src/main/java/baritone/utils/PathingControlManager.java +++ b/src/main/java/baritone/utils/PathingControlManager.java @@ -92,8 +92,8 @@ public class PathingControlManager implements IPathingControlManager { p.secretInternalSetGoal(null); return; } - if (inControlThisTick != inControlLastTick && command.commandType != PathingCommandType.REQUEST_PAUSE) { - // if control has changed, and the new process wants to do something + if (inControlThisTick != inControlLastTick && command.commandType != PathingCommandType.REQUEST_PAUSE && inControlLastTick != null && !inControlLastTick.isTemporary()) { + // if control has changed from a real process to another real process, and the new process wants to do something p.cancelSegmentIfSafe(); // get rid of the in progress stuff from the last process } @@ -200,10 +200,10 @@ public class PathingControlManager implements IPathingControlManager { PathingCommand exec = proc.onTick(Objects.equals(proc, inControlLastTick) && baritone.getPathingBehavior().calcFailedLastTick(), baritone.getPathingBehavior().isSafeToCancel()); if (exec == null) { if (proc.isActive()) { - throw new IllegalStateException(proc.displayName() + " returned null PathingCommand"); + throw new IllegalStateException(proc.displayName() + " actively returned null PathingCommand"); } - proc.onLostControl(); - } else { + // no need to call onLostControl; they are reporting inactive. + } else if (exec.commandType != PathingCommandType.DEFER) { inControlThisTick = proc; if (!proc.isTemporary()) { iterator.forEachRemaining(IBaritoneProcess::onLostControl); diff --git a/src/main/java/baritone/utils/ToolSet.java b/src/main/java/baritone/utils/ToolSet.java index ca45190c7..6fd032550 100644 --- a/src/main/java/baritone/utils/ToolSet.java +++ b/src/main/java/baritone/utils/ToolSet.java @@ -64,10 +64,10 @@ public class ToolSet { } /** - * Using the best tool on the hotbar, how long would it take to mine this block + * Using the best tool on the hotbar, how fast we can mine this block * * @param state the blockstate to be mined - * @return how long it would take in ticks + * @return the speed of how fast we'll mine it. 1/(time in ticks) */ public double getStrVsBlock(IBlockState state) { return breakStrengthCache.computeIfAbsent(state.getBlock(), backendCalculation); @@ -121,7 +121,11 @@ public class ToolSet { */ private double getBestDestructionTime(Block b) { ItemStack stack = player.inventory.getStackInSlot(getBestSlot(b)); - return calculateSpeedVsBlock(stack, b.getDefaultState()); + return calculateSpeedVsBlock(stack, b.getDefaultState()) * avoidanceMultiplier(b); + } + + private double avoidanceMultiplier(Block b) { + return Baritone.settings().blocksToAvoidBreaking.value.contains(b) ? 0.1 : 1; } /** diff --git a/src/main/java/baritone/utils/pathing/Favoring.java b/src/main/java/baritone/utils/pathing/Favoring.java index 8a6017582..56ccb0069 100644 --- a/src/main/java/baritone/utils/pathing/Favoring.java +++ b/src/main/java/baritone/utils/pathing/Favoring.java @@ -19,6 +19,7 @@ package baritone.utils.pathing; import baritone.api.pathing.calc.IPath; import baritone.api.utils.BetterBlockPos; +import baritone.api.utils.Helper; import baritone.api.utils.IPlayerContext; import baritone.pathing.movement.CalculationContext; import it.unimi.dsi.fastutil.longs.Long2DoubleOpenHashMap; @@ -31,7 +32,7 @@ public final class Favoring { for (Avoidance avoid : Avoidance.create(ctx)) { avoid.applySpherical(favorings); } - System.out.println("Favoring size: " + favorings.size()); + Helper.HELPER.logDebug("Favoring size: " + favorings.size()); } public Favoring(IPath previous, CalculationContext context) { // create one just from previous path, no mob avoidances diff --git a/src/main/java/baritone/utils/player/PrimaryPlayerContext.java b/src/main/java/baritone/utils/player/PrimaryPlayerContext.java index 20fe98366..3cb498acd 100644 --- a/src/main/java/baritone/utils/player/PrimaryPlayerContext.java +++ b/src/main/java/baritone/utils/player/PrimaryPlayerContext.java @@ -19,10 +19,10 @@ package baritone.utils.player; import baritone.api.BaritoneAPI; import baritone.api.cache.IWorldData; +import baritone.api.utils.Helper; import baritone.api.utils.IPlayerContext; import baritone.api.utils.IPlayerController; import baritone.api.utils.RayTraceUtils; -import baritone.utils.Helper; import net.minecraft.client.entity.EntityPlayerSP; import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; diff --git a/src/main/java/baritone/utils/player/PrimaryPlayerController.java b/src/main/java/baritone/utils/player/PrimaryPlayerController.java index b9828c803..120f996cc 100644 --- a/src/main/java/baritone/utils/player/PrimaryPlayerController.java +++ b/src/main/java/baritone/utils/player/PrimaryPlayerController.java @@ -17,8 +17,8 @@ package baritone.utils.player; +import baritone.api.utils.Helper; import baritone.api.utils.IPlayerController; -import baritone.utils.Helper; import net.minecraft.client.entity.EntityPlayerSP; import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.entity.player.EntityPlayer;