2018-08-08 03:16:53 +00:00
|
|
|
/*
|
|
|
|
* This file is part of Baritone.
|
|
|
|
*
|
|
|
|
* Baritone is free software: you can redistribute it and/or modify
|
2018-09-17 22:11:40 +00:00
|
|
|
* it under the terms of the GNU Lesser General Public License as published by
|
2018-08-08 03:16:53 +00:00
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
2018-08-08 04:15:22 +00:00
|
|
|
* Baritone is distributed in the hope that it will be useful,
|
2018-08-08 03:16:53 +00:00
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
2018-09-17 22:11:40 +00:00
|
|
|
* GNU Lesser General Public License for more details.
|
2018-08-08 03:16:53 +00:00
|
|
|
*
|
2018-09-17 22:11:40 +00:00
|
|
|
* You should have received a copy of the GNU Lesser General Public License
|
2018-08-08 03:16:53 +00:00
|
|
|
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2018-08-22 20:15:56 +00:00
|
|
|
package baritone.utils;
|
2018-08-01 15:34:35 +00:00
|
|
|
|
2018-09-05 00:13:42 +00:00
|
|
|
import baritone.Baritone;
|
2018-08-01 15:34:35 +00:00
|
|
|
import net.minecraft.block.Block;
|
2018-08-01 15:42:42 +00:00
|
|
|
import net.minecraft.block.state.IBlockState;
|
2018-11-10 01:21:02 +00:00
|
|
|
import net.minecraft.client.entity.EntityPlayerSP;
|
2018-09-05 00:13:42 +00:00
|
|
|
import net.minecraft.enchantment.EnchantmentHelper;
|
|
|
|
import net.minecraft.init.Enchantments;
|
|
|
|
import net.minecraft.init.MobEffects;
|
2018-08-01 15:34:35 +00:00
|
|
|
import net.minecraft.item.ItemStack;
|
2018-10-23 04:41:59 +00:00
|
|
|
import net.minecraft.item.ItemTool;
|
2018-08-01 15:34:35 +00:00
|
|
|
|
2018-08-02 17:49:31 +00:00
|
|
|
import java.util.HashMap;
|
|
|
|
import java.util.Map;
|
2018-10-23 04:41:59 +00:00
|
|
|
import java.util.function.Function;
|
2018-08-02 17:49:31 +00:00
|
|
|
|
2018-08-01 15:34:35 +00:00
|
|
|
/**
|
2018-08-02 17:49:31 +00:00
|
|
|
* A cached list of the best tools on the hotbar for any block
|
2018-08-01 15:34:35 +00:00
|
|
|
*
|
2018-10-23 04:41:59 +00:00
|
|
|
* @author Avery, Brady, leijurv
|
2018-08-01 15:34:35 +00:00
|
|
|
*/
|
2018-11-10 01:21:02 +00:00
|
|
|
public class ToolSet {
|
2019-09-19 20:40:46 +00:00
|
|
|
|
2018-08-23 02:33:56 +00:00
|
|
|
/**
|
2018-09-04 17:06:48 +00:00
|
|
|
* A cache mapping a {@link Block} to how long it will take to break
|
2018-08-23 02:33:56 +00:00
|
|
|
* with this toolset, given the optimum tool is used.
|
|
|
|
*/
|
2018-10-23 04:41:59 +00:00
|
|
|
private final Map<Block, Double> breakStrengthCache;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* My buddy leijurv owned me so we have this to not create a new lambda instance.
|
|
|
|
*/
|
|
|
|
private final Function<Block, Double> backendCalculation;
|
|
|
|
|
2018-11-10 01:21:02 +00:00
|
|
|
private final EntityPlayerSP player;
|
|
|
|
|
|
|
|
public ToolSet(EntityPlayerSP player) {
|
2018-10-23 04:41:59 +00:00
|
|
|
breakStrengthCache = new HashMap<>();
|
2018-11-10 01:21:02 +00:00
|
|
|
this.player = player;
|
2018-10-23 04:41:59 +00:00
|
|
|
|
2019-03-05 05:30:04 +00:00
|
|
|
if (Baritone.settings().considerPotionEffects.value) {
|
2018-10-23 04:41:59 +00:00
|
|
|
double amplifier = potionAmplifier();
|
|
|
|
Function<Double, Double> amplify = x -> amplifier * x;
|
|
|
|
backendCalculation = amplify.compose(this::getBestDestructionTime);
|
|
|
|
} else {
|
|
|
|
backendCalculation = this::getBestDestructionTime;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2019-05-01 17:48:17 +00:00
|
|
|
* Using the best tool on the hotbar, how fast we can mine this block
|
2018-10-23 04:41:59 +00:00
|
|
|
*
|
|
|
|
* @param state the blockstate to be mined
|
2019-05-01 17:48:17 +00:00
|
|
|
* @return the speed of how fast we'll mine it. 1/(time in ticks)
|
2018-10-23 04:41:59 +00:00
|
|
|
*/
|
|
|
|
public double getStrVsBlock(IBlockState state) {
|
|
|
|
return breakStrengthCache.computeIfAbsent(state.getBlock(), backendCalculation);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2019-03-08 20:30:43 +00:00
|
|
|
* Evaluate the material cost of a possible tool. Will return 1 for tools, -1 for other
|
2018-10-23 04:41:59 +00:00
|
|
|
*
|
|
|
|
* @param itemStack a possibly empty ItemStack
|
2019-03-08 20:30:43 +00:00
|
|
|
* @return Either 1 or -1
|
2018-10-23 04:41:59 +00:00
|
|
|
*/
|
|
|
|
private int getMaterialCost(ItemStack itemStack) {
|
2019-03-08 20:30:43 +00:00
|
|
|
return itemStack.getItem() instanceof ItemTool ? 1 : -1;
|
2018-10-23 04:41:59 +00:00
|
|
|
}
|
2018-08-01 15:42:42 +00:00
|
|
|
|
2019-09-01 21:45:31 +00:00
|
|
|
public boolean hasSilkTouch(ItemStack stack) {
|
|
|
|
return EnchantmentHelper.getEnchantmentLevel(Enchantments.SILK_TOUCH, stack) > 0;
|
|
|
|
}
|
|
|
|
|
2018-08-02 17:49:31 +00:00
|
|
|
/**
|
2020-08-14 20:47:39 +00:00
|
|
|
* Calculate which tool on the hotbar is best for mining, depending on an override setting,
|
|
|
|
* related to auto tool movement cost, it will either return current selected slot, or the best slot.
|
2018-08-02 17:49:31 +00:00
|
|
|
*
|
|
|
|
* @param b the blockstate to be mined
|
2019-10-11 00:47:26 +00:00
|
|
|
* @return An int containing the index in the tools array that worked best
|
2018-08-02 17:49:31 +00:00
|
|
|
*/
|
2020-08-14 15:55:10 +00:00
|
|
|
|
2019-10-11 00:47:26 +00:00
|
|
|
public int getBestSlot(Block b, boolean preferSilkTouch) {
|
2020-08-14 15:55:10 +00:00
|
|
|
return getBestSlot(b, preferSilkTouch, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getBestSlot(Block b, boolean preferSilkTouch, boolean pathingCalculation) {
|
2020-08-14 20:47:39 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
If we actually want know what efficiency our held item has instead of the best one
|
2020-08-17 23:03:04 +00:00
|
|
|
possible, this lets us make pathing depend on the actual tool to be used (if auto tool is disabled)
|
2020-08-14 20:47:39 +00:00
|
|
|
*/
|
2020-08-17 23:03:04 +00:00
|
|
|
if (Baritone.settings().disableAutoTool.value && pathingCalculation) {
|
2020-08-14 08:14:02 +00:00
|
|
|
return player.inventory.currentItem;
|
|
|
|
}
|
|
|
|
|
2019-10-11 00:47:26 +00:00
|
|
|
int best = 0;
|
2019-09-01 21:45:31 +00:00
|
|
|
double highestSpeed = Double.NEGATIVE_INFINITY;
|
|
|
|
int lowestCost = Integer.MIN_VALUE;
|
|
|
|
boolean bestSilkTouch = false;
|
2018-10-23 04:41:59 +00:00
|
|
|
IBlockState blockState = b.getDefaultState();
|
2019-10-11 00:47:26 +00:00
|
|
|
for (int i = 0; i < 9; i++) {
|
2018-11-10 01:21:02 +00:00
|
|
|
ItemStack itemStack = player.inventory.getStackInSlot(i);
|
2019-09-01 21:45:31 +00:00
|
|
|
double speed = calculateSpeedVsBlock(itemStack, blockState);
|
|
|
|
boolean silkTouch = hasSilkTouch(itemStack);
|
|
|
|
if (speed > highestSpeed) {
|
|
|
|
highestSpeed = speed;
|
2018-08-01 15:34:35 +00:00
|
|
|
best = i;
|
2019-09-01 21:45:31 +00:00
|
|
|
lowestCost = getMaterialCost(itemStack);
|
|
|
|
bestSilkTouch = silkTouch;
|
|
|
|
} else if (speed == highestSpeed) {
|
|
|
|
int cost = getMaterialCost(itemStack);
|
2019-09-01 22:18:59 +00:00
|
|
|
if ((cost < lowestCost && (silkTouch || !bestSilkTouch)) ||
|
2019-09-19 19:53:15 +00:00
|
|
|
(preferSilkTouch && !bestSilkTouch && silkTouch)) {
|
2019-09-01 21:45:31 +00:00
|
|
|
highestSpeed = speed;
|
2018-10-23 04:41:59 +00:00
|
|
|
best = i;
|
2019-09-01 21:45:31 +00:00
|
|
|
lowestCost = cost;
|
|
|
|
bestSilkTouch = silkTouch;
|
2018-10-23 04:41:59 +00:00
|
|
|
}
|
2018-08-01 15:34:35 +00:00
|
|
|
}
|
|
|
|
}
|
2018-08-01 18:05:35 +00:00
|
|
|
return best;
|
2018-08-01 15:34:35 +00:00
|
|
|
}
|
2018-08-01 15:42:42 +00:00
|
|
|
|
2018-08-02 17:49:31 +00:00
|
|
|
/**
|
2018-10-23 04:41:59 +00:00
|
|
|
* Calculate how effectively a block can be destroyed
|
2018-08-02 17:49:31 +00:00
|
|
|
*
|
2018-10-23 04:41:59 +00:00
|
|
|
* @param b the blockstate to be mined
|
|
|
|
* @return A double containing the destruction ticks with the best tool
|
2018-08-02 17:49:31 +00:00
|
|
|
*/
|
2018-10-23 04:41:59 +00:00
|
|
|
private double getBestDestructionTime(Block b) {
|
2020-08-14 15:55:10 +00:00
|
|
|
ItemStack stack = player.inventory.getStackInSlot(getBestSlot(b, false, true));
|
2019-05-01 17:48:17 +00:00
|
|
|
return calculateSpeedVsBlock(stack, b.getDefaultState()) * avoidanceMultiplier(b);
|
|
|
|
}
|
|
|
|
|
|
|
|
private double avoidanceMultiplier(Block b) {
|
|
|
|
return Baritone.settings().blocksToAvoidBreaking.value.contains(b) ? 0.1 : 1;
|
2018-08-23 02:33:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Calculates how long would it take to mine the specified block given the best tool
|
2018-09-08 00:00:36 +00:00
|
|
|
* in this toolset is used. A negative value is returned if the specified block is unbreakable.
|
2018-08-23 02:33:56 +00:00
|
|
|
*
|
2019-01-28 19:30:33 +00:00
|
|
|
* @param item the item to mine it with
|
2018-08-23 02:33:56 +00:00
|
|
|
* @param state the blockstate to be mined
|
2019-01-28 19:56:44 +00:00
|
|
|
* @return how long it would take in ticks
|
2018-08-23 02:33:56 +00:00
|
|
|
*/
|
2019-01-15 03:52:31 +00:00
|
|
|
public static double calculateSpeedVsBlock(ItemStack item, IBlockState state) {
|
2018-10-23 04:41:59 +00:00
|
|
|
float hardness = state.getBlockHardness(null, null);
|
|
|
|
if (hardness < 0) {
|
2018-09-08 00:00:36 +00:00
|
|
|
return -1;
|
2018-09-08 04:32:25 +00:00
|
|
|
}
|
2018-08-21 01:32:18 +00:00
|
|
|
|
2018-10-23 04:41:59 +00:00
|
|
|
float speed = item.getDestroySpeed(state);
|
2018-09-05 00:13:42 +00:00
|
|
|
if (speed > 1) {
|
2018-10-23 04:41:59 +00:00
|
|
|
int effLevel = EnchantmentHelper.getEnchantmentLevel(Enchantments.EFFICIENCY, item);
|
|
|
|
if (effLevel > 0 && !item.isEmpty()) {
|
2018-09-05 00:13:42 +00:00
|
|
|
speed += effLevel * effLevel + 1;
|
|
|
|
}
|
2018-08-21 01:32:18 +00:00
|
|
|
}
|
|
|
|
|
2018-10-23 04:41:59 +00:00
|
|
|
speed /= hardness;
|
|
|
|
if (state.getMaterial().isToolNotRequired() || (!item.isEmpty() && item.canHarvestBlock(state))) {
|
2019-01-16 01:21:50 +00:00
|
|
|
return speed / 30;
|
2018-09-05 00:13:42 +00:00
|
|
|
} else {
|
2019-01-16 01:21:50 +00:00
|
|
|
return speed / 100;
|
2018-10-23 04:41:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Calculates any modifier to breaking time based on status effects.
|
|
|
|
*
|
|
|
|
* @return a double to scale block breaking speed.
|
|
|
|
*/
|
|
|
|
private double potionAmplifier() {
|
|
|
|
double speed = 1;
|
2018-11-10 01:21:02 +00:00
|
|
|
if (player.isPotionActive(MobEffects.HASTE)) {
|
|
|
|
speed *= 1 + (player.getActivePotionEffect(MobEffects.HASTE).getAmplifier() + 1) * 0.2;
|
2018-10-23 04:41:59 +00:00
|
|
|
}
|
2018-11-10 01:21:02 +00:00
|
|
|
if (player.isPotionActive(MobEffects.MINING_FATIGUE)) {
|
|
|
|
switch (player.getActivePotionEffect(MobEffects.MINING_FATIGUE).getAmplifier()) {
|
2018-10-23 04:41:59 +00:00
|
|
|
case 0:
|
|
|
|
speed *= 0.3;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
speed *= 0.09;
|
|
|
|
break;
|
|
|
|
case 2:
|
2019-01-05 07:37:00 +00:00
|
|
|
speed *= 0.0027; // you might think that 0.09*0.3 = 0.027 so that should be next, that would make too much sense. it's 0.0027.
|
2018-10-23 04:41:59 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
speed *= 0.00081;
|
|
|
|
break;
|
|
|
|
}
|
2018-08-21 01:32:18 +00:00
|
|
|
}
|
2018-10-23 04:41:59 +00:00
|
|
|
return speed;
|
2018-08-21 01:32:18 +00:00
|
|
|
}
|
2018-08-01 15:34:35 +00:00
|
|
|
}
|