diff --git a/src/main/java/baritone/behavior/InventoryBehavior.java b/src/main/java/baritone/behavior/InventoryBehavior.java index a07b5db28..c0a3abc92 100644 --- a/src/main/java/baritone/behavior/InventoryBehavior.java +++ b/src/main/java/baritone/behavior/InventoryBehavior.java @@ -23,7 +23,8 @@ import baritone.api.utils.InventorySlot; import baritone.api.utils.Pair; import baritone.utils.ToolSet; -import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; +import it.unimi.dsi.fastutil.objects.Reference2BooleanMap; +import it.unimi.dsi.fastutil.objects.Reference2BooleanOpenHashMap; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.player.EntityPlayer; @@ -140,6 +141,7 @@ private boolean requestSwapWithHotBar(int inInventory, int inHotbar) { } private InventorySlot bestToolAgainst(final Block against, final Class cla$$) { + // TODO: Replace with ToolSet.getBestSlot return this.findBestSlotMatching( Comparator.comparingDouble(stack -> ToolSet.calculateSpeedVsBlock(stack, against.getDefaultState())), stack -> { @@ -189,11 +191,11 @@ public boolean selectThrowawayForLocation(boolean select, int x, int y, int z) { } public boolean canSelectItem(Predicate desired) { - return this.resolveSelectionStrategy(desired) != null; + return this.resolveSelectionStrategy(this.findSlotMatching(desired)) != null; } public boolean trySelectItem(Predicate desired) { - final SelectionStrategy strategy = this.resolveSelectionStrategy(desired); + final SelectionStrategy strategy = this.resolveSelectionStrategy(this.findSlotMatching(desired)); if (strategy != null) { strategy.run(); // TODO: Consider cases where returning the SelectionType is needed/useful to the caller @@ -202,8 +204,7 @@ public boolean trySelectItem(Predicate desired) { return false; } - public SelectionStrategy resolveSelectionStrategy(Predicate desired) { - final InventorySlot slot = this.findSlotMatching(desired); + public SelectionStrategy resolveSelectionStrategy(final InventorySlot slot) { if (slot != null) { switch (slot.getType()) { case HOTBAR: @@ -232,6 +233,7 @@ public SelectionStrategy resolveSelectionStrategy(Predicate d if (this.canAccessInventory()) { return SelectionStrategy.of(SelectionType.ENQUEUED, () -> { // TODO: Determine if hotbar swap can be immediate, and return type accordingly + // Also don't only swap into slot 7 that's silly requestSwapWithHotBar(slot.getInventoryIndex(), 7); ctx.player().inventory.currentItem = 7; }); @@ -244,6 +246,14 @@ public SelectionStrategy resolveSelectionStrategy(Predicate d return null; } + public InventorySlot findBestAccessibleMatching(final Comparator comparator, + final Predicate filter) { + final Stream> accessible = this.canAccessInventory() + ? ctx.inventory().allSlots() + : Stream.concat(ctx.inventory().hotbarSlots(), Stream.of(ctx.inventory().offhand())); + return this.findBestMatching0(accessible, comparator, filter); + } + public InventorySlot findSlotMatching(final Predicate filter) { return this.findBestSlotMatching(null, filter); } @@ -320,7 +330,7 @@ public enum SelectionType { private static final class ItemInteractionHelper { - private static final Map, Boolean> CACHE = new Reference2ReferenceOpenHashMap<>(); + private static final Reference2BooleanMap> CACHE = new Reference2BooleanOpenHashMap<>(); public static boolean couldInteract(final ItemStack stack) { if (stack.isEmpty()) { diff --git a/src/main/java/baritone/pathing/movement/MovementHelper.java b/src/main/java/baritone/pathing/movement/MovementHelper.java index 7e8044e9b..63abf3a59 100644 --- a/src/main/java/baritone/pathing/movement/MovementHelper.java +++ b/src/main/java/baritone/pathing/movement/MovementHelper.java @@ -18,12 +18,12 @@ package baritone.pathing.movement; import baritone.Baritone; -import baritone.api.BaritoneAPI; import baritone.api.IBaritone; import baritone.api.pathing.movement.ActionCosts; import baritone.api.pathing.movement.MovementStatus; import baritone.api.utils.*; import baritone.api.utils.input.Input; +import baritone.behavior.InventoryBehavior; import baritone.pathing.movement.MovementState.MovementTarget; import baritone.pathing.precompute.Ternary; import baritone.utils.BlockStateInterface; @@ -592,8 +592,13 @@ static void switchToBestToolFor(IPlayerContext ctx, IBlockState state) { * @param ts Previously calculated ToolSet */ static void switchToBestToolFor(IPlayerContext ctx, IBlockState state, ToolSet ts, boolean preferSilkTouch) { - if (Baritone.settings().autoTool.value && !Baritone.settings().assumeExternalAutoTool.value) { - ctx.player().inventory.currentItem = ts.getBestSlot(state, preferSilkTouch, false); + if (ToolSet.isAutoTool()) { + // TODO: Submit through InventoryBehavior, instead of executing the strategy here + final InventorySlot slot = ts.getBestSlot(state, preferSilkTouch); + final InventoryBehavior.SelectionStrategy strategy = ((Baritone) ctx.baritone()).getInventoryBehavior().resolveSelectionStrategy(slot); + if (strategy != null) { + strategy.run(); + } } } diff --git a/src/main/java/baritone/utils/ToolSet.java b/src/main/java/baritone/utils/ToolSet.java index 95ace30cf..267d58af6 100644 --- a/src/main/java/baritone/utils/ToolSet.java +++ b/src/main/java/baritone/utils/ToolSet.java @@ -20,6 +20,7 @@ import baritone.Baritone; import baritone.PerformanceCritical; import baritone.api.utils.IPlayerContext; +import baritone.api.utils.InventorySlot; import baritone.utils.accessor.IItemTool; import it.unimi.dsi.fastutil.HashCommon; import it.unimi.dsi.fastutil.objects.Reference2DoubleOpenHashMap; @@ -27,11 +28,13 @@ import net.minecraft.block.state.IBlockState; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.init.Enchantments; +import net.minecraft.init.Items; import net.minecraft.init.MobEffects; import net.minecraft.item.ItemStack; import net.minecraft.item.ItemSword; import net.minecraft.item.ItemTool; +import java.util.Comparator; import java.util.function.ToDoubleFunction; /** @@ -84,7 +87,9 @@ public double getStrVsBlock(IBlockState state) { * @return A double containing the destruction speed with the best tool */ private double getBestDestructionSpeed(IBlockState state) { - final ItemStack stack = ctx.player().inventory.getStackInSlot(this.getBestSlot(state, false, true)); + final ItemStack stack = isAutoTool() + ? ctx.inventory().itemAt(this.getBestSlot(state, false)) + : ctx.player().getHeldItemMainhand(); return calculateSpeedVsBlock(stack, state) * avoidanceMultiplier(state.getBlock()); } @@ -93,13 +98,12 @@ private double getBestDestructionSpeed(IBlockState state) { * harvest level order; there is a chance for multiple at the same with modded tools * but in that case we don't really care. * - * @param itemStack a possibly empty ItemStack + * @param stack a possibly empty ItemStack * @return The tool's harvest level, or {@code -1} if the stack isn't a tool */ - private static int getMaterialCost(ItemStack itemStack) { - if (itemStack.getItem() instanceof ItemTool) { - ItemTool tool = (ItemTool) itemStack.getItem(); - return ((IItemTool) tool).getHarvestLevel(); + private static int getMaterialCost(ItemStack stack) { + if (stack.getItem() instanceof IItemTool) { + return ((IItemTool) stack.getItem()).getHarvestLevel(); } else { return -1; } @@ -111,51 +115,36 @@ private static int getMaterialCost(ItemStack itemStack) { * * @param state the blockstate to be mined * @param preferSilkTouch whether to prefer silk touch tools - * @param pathingCalculation whether the call to this method is for pathing calculation * @return An int containing the index in the tools array that worked best */ - public int getBestSlot(IBlockState state, boolean preferSilkTouch, boolean pathingCalculation) { + public InventorySlot getBestSlot(IBlockState state, boolean preferSilkTouch) { + final Comparator compare = Comparator + // Prioritize mining speed over everything + .comparingDouble(stack -> calculateSpeedVsBlock(stack, state)) + // Prioritize silk touch tools, if preferSilkTouch is true, over reduced material cost + .thenComparing(ToolSet::hasSilkTouch, (a, b) -> preferSilkTouch ? Boolean.compare(a, b) : 0) + // Minimize material cost + .thenComparing(Comparator.comparingInt(ToolSet::getMaterialCost).reversed()); - /* - If we actually want know what efficiency our held item has instead of the best one - possible, this lets us make pathing depend on the actual tool to be used (if auto tool is disabled) - */ - if (!Baritone.settings().autoTool.value && pathingCalculation) { - return ctx.player().inventory.currentItem; - } - - int best = 0; - double highestSpeed = Double.NEGATIVE_INFINITY; - int lowestCost = Integer.MIN_VALUE; - boolean bestSilkTouch = false; - for (int i = 0; i < 9; i++) { - ItemStack itemStack = ctx.player().inventory.getStackInSlot(i); - if (!Baritone.settings().useSwordToMine.value && itemStack.getItem() instanceof ItemSword) { - continue; - } - - if (Baritone.settings().itemSaver.value && (itemStack.getItemDamage() + Baritone.settings().itemSaverThreshold.value) >= itemStack.getMaxDamage() && itemStack.getMaxDamage() > 1) { - continue; - } - double speed = calculateSpeedVsBlock(itemStack, state); - boolean silkTouch = hasSilkTouch(itemStack); - if (speed > highestSpeed) { - highestSpeed = speed; - best = i; - lowestCost = getMaterialCost(itemStack); - bestSilkTouch = silkTouch; - } else if (speed == highestSpeed) { - int cost = getMaterialCost(itemStack); - if ((cost < lowestCost && (silkTouch || !bestSilkTouch)) || - (preferSilkTouch && !bestSilkTouch && silkTouch)) { - highestSpeed = speed; - best = i; - lowestCost = cost; - bestSilkTouch = silkTouch; + return ((Baritone) ctx.baritone()).getInventoryBehavior().findBestAccessibleMatching( + compare, + stack -> { + if (!Baritone.settings().useSwordToMine.value && stack.getItem() instanceof ItemSword) { + return false; + } + if (Baritone.settings().itemSaver.value + && stack.getItemDamage() + Baritone.settings().itemSaverThreshold.value >= stack.getMaxDamage() + && stack.getMaxDamage() > 1 + ) { + return false; + } + return true; } - } - } - return best; + ); + } + + public static boolean isAutoTool() { + return Baritone.settings().autoTool.value && !Baritone.settings().assumeExternalAutoTool.value; } /**