baritone/src/main/java/baritone/utils/ToolSet.java

207 lines
7.3 KiB
Java
Raw Normal View History

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
* 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.
*
* 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
* GNU Lesser General Public License for more details.
2018-08-08 03:16:53 +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
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;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.init.Enchantments;
import net.minecraft.init.MobEffects;
2018-10-23 04:41:59 +00:00
import net.minecraft.item.Item.ToolMaterial;
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
*/
public class ToolSet {
2019-09-19 20:40:46 +00:00
/**
2018-09-04 17:06:48 +00:00
* A cache mapping a {@link Block} to how long it will take to break
* 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;
private final EntityPlayerSP player;
public ToolSet(EntityPlayerSP player) {
2018-10-23 04:41:59 +00:00
breakStrengthCache = new HashMap<>();
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;
}
}
/**
* 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
* @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);
}
/**
* Evaluate the material cost of a possible tool. The priority matches the
* listed order in the Item.ToolMaterial enum.
*
* @param itemStack a possibly empty ItemStack
* @return values range from -1 to 4
*/
private int getMaterialCost(ItemStack itemStack) {
if (itemStack.getItem() instanceof ItemTool) {
ItemTool tool = (ItemTool) itemStack.getItem();
return ToolMaterial.valueOf(tool.getToolMaterialName()).ordinal();
} else {
return -1;
}
}
2018-08-01 15:42:42 +00:00
public boolean hasSilkTouch(ItemStack stack) {
return EnchantmentHelper.getEnchantmentLevel(Enchantments.SILK_TOUCH, stack) > 0;
}
2018-08-02 17:49:31 +00:00
/**
* Calculate which tool on the hotbar is best for mining
*
* @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
*/
2019-10-11 00:47:26 +00:00
public int getBestSlot(Block b, boolean preferSilkTouch) {
int best = 0;
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++) {
ItemStack itemStack = player.inventory.getStackInSlot(i);
double speed = calculateSpeedVsBlock(itemStack, blockState);
boolean silkTouch = hasSilkTouch(itemStack);
if (speed > highestSpeed) {
highestSpeed = speed;
2018-08-01 15:34:35 +00:00
best = i;
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)) {
highestSpeed = speed;
2018-10-23 04:41:59 +00:00
best = i;
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) {
ItemStack stack = player.inventory.getStackInSlot(getBestSlot(b, false));
return calculateSpeedVsBlock(stack, b.getDefaultState()) * avoidanceMultiplier(b);
}
private double avoidanceMultiplier(Block b) {
return Baritone.settings().blocksToAvoidBreaking.value.contains(b) ? 0.1 : 1;
}
/**
* Calculates how long would it take to mine the specified block given the best tool
* in this toolset is used. A negative value is returned if the specified block is unbreakable.
*
2019-01-28 19:30:33 +00:00
* @param item the item to mine it with
* @param state the blockstate to be mined
2019-01-28 19:56:44 +00:00
* @return how long it would take in ticks
*/
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) {
return -1;
2018-09-08 04:32:25 +00:00
}
2018-10-23 04:41:59 +00:00
float speed = item.getDestroySpeed(state);
if (speed > 1) {
2018-10-23 04:41:59 +00:00
int effLevel = EnchantmentHelper.getEnchantmentLevel(Enchantments.EFFICIENCY, item);
if (effLevel > 0 && !item.isEmpty()) {
speed += effLevel * effLevel + 1;
}
}
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;
} 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;
if (player.isPotionActive(MobEffects.HASTE)) {
speed *= 1 + (player.getActivePotionEffect(MobEffects.HASTE).getAmplifier() + 1) * 0.2;
2018-10-23 04:41:59 +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-10-23 04:41:59 +00:00
return speed;
}
2018-08-01 15:34:35 +00:00
}