tool set, fixes #227

This commit is contained in:
ave4224 2018-10-23 00:41:59 -04:00
parent b55d96169f
commit 9a1aecc002
No known key found for this signature in database
GPG Key ID: 21788F5878E22F0A
2 changed files with 115 additions and 59 deletions

View File

@ -400,7 +400,7 @@ public interface MovementHelper extends ActionCosts, Helper {
* @param ts previously calculated ToolSet * @param ts previously calculated ToolSet
*/ */
static void switchToBestToolFor(IBlockState b, ToolSet ts) { static void switchToBestToolFor(IBlockState b, ToolSet ts) {
mc.player.inventory.currentItem = ts.getBestSlot(b); mc.player.inventory.currentItem = ts.getBestSlot(b.getBlock());
} }
static boolean throwaway(boolean select) { static boolean throwaway(boolean select) {

View File

@ -23,42 +23,42 @@ import net.minecraft.block.state.IBlockState;
import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.init.Enchantments; import net.minecraft.init.Enchantments;
import net.minecraft.init.MobEffects; import net.minecraft.init.MobEffects;
import net.minecraft.item.Item.ToolMaterial;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemTool;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.function.Function;
/** /**
* A cached list of the best tools on the hotbar for any block * A cached list of the best tools on the hotbar for any block
* *
* @author avecowa, Brady, leijurv * @author Avery, Brady, leijurv
*/ */
public class ToolSet implements Helper { public class ToolSet implements Helper {
/** /**
* A cache mapping a {@link Block} to how long it will take to break * A cache mapping a {@link Block} to how long it will take to break
* with this toolset, given the optimum tool is used. * with this toolset, given the optimum tool is used.
*/ */
private Map<Block, Double> breakStrengthCache = new HashMap<>(); private final Map<Block, Double> breakStrengthCache;
/** /**
* Calculate which tool on the hotbar is best for mining * My buddy leijurv owned me so we have this to not create a new lambda instance.
*
* @param b the blockstate to be mined
* @return a byte indicating the index in the tools array that worked best
*/ */
public byte getBestSlot(IBlockState b) { private final Function<Block, Double> backendCalculation;
byte best = 0;
double value = -1; public ToolSet() {
for (byte i = 0; i < 9; i++) { breakStrengthCache = new HashMap<>();
double v = calculateStrVsBlock(i, b);
if (v > value || value == -1) { if (Baritone.settings().considerPotionEffects.get()) {
value = v; double amplifier = potionAmplifier();
best = i; Function<Double, Double> amplify = x -> amplifier * x;
backendCalculation = amplify.compose(this::getBestDestructionTime);
} else {
backendCalculation = this::getBestDestructionTime;
} }
} }
return best;
}
/** /**
* Using the best tool on the hotbar, how long would it take to mine this block * Using the best tool on the hotbar, how long would it take to mine this block
@ -67,14 +67,64 @@ public class ToolSet implements Helper {
* @return how long it would take in ticks * @return how long it would take in ticks
*/ */
public double getStrVsBlock(IBlockState state) { public double getStrVsBlock(IBlockState state) {
Double strength = this.breakStrengthCache.get(state.getBlock()); return breakStrengthCache.computeIfAbsent(state.getBlock(), backendCalculation);
if (strength != null) {
// the function will take this path >99% of the time
return strength;
} }
double str = calculateStrVsBlock(getBestSlot(state), state);
this.breakStrengthCache.put(state.getBlock(), str); /**
return str; * 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;
}
}
/**
* Calculate which tool on the hotbar is best for mining
*
* @param b the blockstate to be mined
* @return A byte containing the index in the tools array that worked best
*/
public byte getBestSlot(Block b) {
byte best = 0;
double value = Double.NEGATIVE_INFINITY;
int materialCost = Integer.MIN_VALUE;
IBlockState blockState = b.getDefaultState();
for (byte i = 0; i < 9; i++) {
ItemStack itemStack = player().inventory.getStackInSlot(i);
double v = calculateStrVsBlock(itemStack, blockState);
if (v > value) {
value = v;
best = i;
materialCost = getMaterialCost(itemStack);
} else if (v == value) {
int c = getMaterialCost(itemStack);
if (c < materialCost) {
value = v;
best = i;
materialCost = c;
}
}
}
return best;
}
/**
* Calculate how effectively a block can be destroyed
*
* @param b the blockstate to be mined
* @return A double containing the destruction ticks with the best tool
*/
private double getBestDestructionTime(Block b) {
ItemStack stack = player().inventory.getStackInSlot(getBestSlot(b));
return calculateStrVsBlock(stack, b.getDefaultState());
} }
/** /**
@ -84,24 +134,36 @@ public class ToolSet implements Helper {
* @param state the blockstate to be mined * @param state the blockstate to be mined
* @return how long it would take in ticks * @return how long it would take in ticks
*/ */
private double calculateStrVsBlock(byte slot, IBlockState state) { private double calculateStrVsBlock(ItemStack item, IBlockState state) {
// Calculate the slot with the best item float hardness = state.getBlockHardness(null, null);
ItemStack contents = player().inventory.getStackInSlot(slot); if (hardness < 0) {
float blockHard = state.getBlockHardness(null, null);
if (blockHard < 0) {
return -1; return -1;
} }
float speed = contents.getDestroySpeed(state); float speed = item.getDestroySpeed(state);
if (speed > 1) { if (speed > 1) {
int effLevel = EnchantmentHelper.getEnchantmentLevel(Enchantments.EFFICIENCY, contents); int effLevel = EnchantmentHelper.getEnchantmentLevel(Enchantments.EFFICIENCY, item);
if (effLevel > 0 && !contents.isEmpty()) { if (effLevel > 0 && !item.isEmpty()) {
speed += effLevel * effLevel + 1; speed += effLevel * effLevel + 1;
} }
} }
if (Baritone.settings().considerPotionEffects.get()) { speed /= hardness;
if (state.getMaterial().isToolNotRequired() || (!item.isEmpty() && item.canHarvestBlock(state))) {
speed /= 30;
} else {
speed /= 100;
}
return speed;
}
/**
* 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)) { if (player().isPotionActive(MobEffects.HASTE)) {
speed *= 1 + (player().getActivePotionEffect(MobEffects.HASTE).getAmplifier() + 1) * 0.2; speed *= 1 + (player().getActivePotionEffect(MobEffects.HASTE).getAmplifier() + 1) * 0.2;
} }
@ -121,12 +183,6 @@ public class ToolSet implements Helper {
break; break;
} }
} }
} return speed;
speed /= blockHard;
if (state.getMaterial().isToolNotRequired() || (!contents.isEmpty() && contents.canHarvestBlock(state))) {
return speed / 30;
} else {
return speed / 100;
}
} }
} }