Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
public class AutoTool extends Module {
private final SettingGroup sgGeneral = settings.getDefaultGroup();
private final SettingGroup sgWhitelist = settings.createGroup("Whitelist");
private final SettingGroup sgSilk = settings.createGroup("Silk Touch");

// General

Expand All @@ -44,13 +45,21 @@ public class AutoTool extends Module {
.build()
);

private final Setting<Boolean> silkTouchForEnderChest = sgGeneral.add(new BoolSetting.Builder()
.name("silk-touch-for-ender-chest")
.description("Mines Ender Chests only with the Silk Touch enchantment.")
private final Setting<Boolean> silkTouchEnabled = sgSilk.add(new BoolSetting.Builder()
.name("silk Touch Whitelist")
.description("Require Silk Touch for selected blocks.")
.defaultValue(true)
.build()
);

private final Setting<List<Block>> silkTouchBlocks = sgSilk.add(new BlockListSetting.Builder()
.name("Whitelist Blocks")
.description("Blocks that should be mined with Silk Touch.")
.defaultValue(Blocks.ENDER_CHEST, Blocks.GLOWSTONE, Blocks.SEA_LANTERN, Blocks.GLASS, Blocks.TURTLE_EGG, Blocks.ICE, Blocks.BLUE_ICE, Blocks.PACKED_ICE)
.visible(silkTouchEnabled::get)
.build()
);

private final Setting<Boolean> fortuneForOresCrops = sgGeneral.add(new BoolSetting.Builder()
.name("fortune-for-ores-and-crops")
.description("Mines Ores and crops only with the Fortune enchantment.")
Expand Down Expand Up @@ -158,13 +167,15 @@ private void onStartBreakingBlock(StartBreakingBlockEvent event) {
double bestScore = -1;
bestSlot = -1;

boolean enforceSilk = silkTouchEnabled.get() && silkTouchBlocks.get().contains(blockState.getBlock());

for (int i = 0; i < 9; i++) {
ItemStack itemStack = mc.player.getInventory().getStack(i);

if (listMode.get() == ListMode.Whitelist && !whitelist.get().contains(itemStack.getItem())) continue;
if (listMode.get() == ListMode.Blacklist && blacklist.get().contains(itemStack.getItem())) continue;

double score = getScore(itemStack, blockState, silkTouchForEnderChest.get(), fortuneForOresCrops.get(), prefer.get(), itemStack2 -> !shouldStopUsing(itemStack2));
double score = getScore(itemStack, blockState, fortuneForOresCrops.get(), prefer.get(), itemStack2 -> !shouldStopUsing(itemStack2), enforceSilk, silkTouchBlocks.get());
if (score < 0) continue;

if (score > bestScore) {
Expand All @@ -173,7 +184,26 @@ private void onStartBreakingBlock(StartBreakingBlockEvent event) {
}
}

if ((bestSlot != -1 && (bestScore > getScore(currentStack, blockState, silkTouchForEnderChest.get(), fortuneForOresCrops.get(), prefer.get(), itemStack -> !shouldStopUsing(itemStack))) || shouldStopUsing(currentStack) || !isTool(currentStack))) {
// if this is a silk touch target but no silk touch tool exists,
// rerun selection without enforcing silk touch so we still choose a suitable tool
if (bestSlot == -1 && enforceSilk) {
for (int i = 0; i < 9; i++) {
ItemStack itemStack = mc.player.getInventory().getStack(i);

if (listMode.get() == ListMode.Whitelist && !whitelist.get().contains(itemStack.getItem())) continue;
if (listMode.get() == ListMode.Blacklist && blacklist.get().contains(itemStack.getItem())) continue;

double score = getScore(itemStack, blockState, fortuneForOresCrops.get(), prefer.get(), itemStack2 -> !shouldStopUsing(itemStack2), false, silkTouchBlocks.get());
if (score < 0) continue;

if (score > bestScore) {
bestScore = score;
bestSlot = i;
}
}
}

if ((bestSlot != -1 && (bestScore > getScore(currentStack, blockState, fortuneForOresCrops.get(), prefer.get(), itemStack -> !shouldStopUsing(itemStack), silkTouchEnabled.get(), silkTouchBlocks.get())) || shouldStopUsing(currentStack) || !isTool(currentStack))) {
ticks = switchDelay.get();

if (ticks == 0) InvUtils.swap(bestSlot, true);
Expand All @@ -193,20 +223,29 @@ private boolean shouldStopUsing(ItemStack itemStack) {
return antiBreak.get() && (itemStack.getMaxDamage() - itemStack.getDamage()) < (itemStack.getMaxDamage() * breakDurability.get() / 100);
}

public static double getScore(ItemStack itemStack, BlockState state, boolean silkTouchEnderChest, boolean fortuneOre, EnchantPreference enchantPreference, Predicate<ItemStack> good) {
public static double getScore(ItemStack itemStack, BlockState state, boolean fortuneOre, EnchantPreference enchantPreference, Predicate<ItemStack> good, boolean silkTouchEnabled, List<Block> silkBlocks) {
if (!good.test(itemStack) || !isTool(itemStack)) return -1;

boolean isSilkTarget = silkTouchEnabled && silkBlocks.contains(state.getBlock());

// for ender chest, only pickaxes are valid tool (silk touch axes will drop ec but extremely slow, so we pass it)
if (state.getBlock() == Blocks.ENDER_CHEST && !itemStack.isIn(ItemTags.PICKAXES)) return -1;
boolean bypassSuitability = isSilkTarget && allowSilkBypass(state);

// When fortuneForOresCrops is enabled, allow crops to bypass suitability so fortune tools can be considered for crops
if (!bypassSuitability && fortuneOre && (state.getBlock() instanceof CropBlock || state.getBlock() instanceof NetherWartBlock)) bypassSuitability = true;

if (!itemStack.isSuitableFor(state) &&
!bypassSuitability &&
!(itemStack.isIn(ItemTags.SWORDS) && (state.getBlock() instanceof BambooBlock || state.getBlock() instanceof BambooShootBlock)) &&
!(itemStack.getItem() instanceof ShearsItem && state.getBlock() instanceof LeavesBlock || state.isIn(BlockTags.WOOL)))
return -1;

if (silkTouchEnderChest
&& state.getBlock() == Blocks.ENDER_CHEST
&& !Utils.hasEnchantments(itemStack, Enchantments.SILK_TOUCH)) {
return -1;
}
// force usage of silk touch on configured block list
if (isSilkTarget && !Utils.hasEnchantments(itemStack, Enchantments.SILK_TOUCH)) return -1;

if (fortuneOre
&& !isSilkTarget
&& isFortunable(state.getBlock())
&& !Utils.hasEnchantments(itemStack, Enchantments.FORTUNE)) {
return -1;
Expand All @@ -225,9 +264,18 @@ && isFortunable(state.getBlock())
if (itemStack.isIn(ItemTags.SWORDS) && (state.getBlock() instanceof BambooBlock || state.getBlock() instanceof BambooShootBlock))
score += 9000 + (itemStack.get(DataComponentTypes.TOOL).getSpeed(state) * 1000);

// Prefer hoes slightly for crops when fortune is enabled and the block is a crop.
if (fortuneOre && (state.getBlock() instanceof CropBlock || state.getBlock() instanceof NetherWartBlock) && itemStack.isIn(ItemTags.HOES)) score += 10;

return score;
}

private static boolean allowSilkBypass(BlockState state) {
if (state.isToolRequired()) return false;
if (state.isIn(BlockTags.NEEDS_DIAMOND_TOOL) || state.isIn(BlockTags.NEEDS_IRON_TOOL) || state.isIn(BlockTags.NEEDS_STONE_TOOL)) return false;
return true;
}

public static boolean isTool(Item item) {
return isTool(item.getDefaultStack());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.function.Predicate;
Expand Down Expand Up @@ -2092,10 +2093,10 @@ protected int findAndMoveBestToolToHotbar(HighwayBuilder b, BlockState blockStat
int bestSlot = -1;

for (int i = 0; i < b.mc.player.getInventory().getMainStacks().size(); i++) {
double score = AutoTool.getScore(b.mc.player.getInventory().getStack(i), blockState, false, false, AutoTool.EnchantPreference.None, itemStack -> {
double score = AutoTool.getScore(b.mc.player.getInventory().getStack(i), blockState, false, AutoTool.EnchantPreference.None, itemStack -> {
if (noSilkTouch && Utils.hasEnchantment(itemStack, Enchantments.SILK_TOUCH)) return false;
return !b.dontBreakTools.get() || itemStack.getMaxDamage() - itemStack.getDamage() > (itemStack.getMaxDamage() * (b.breakDurability.get() / 100));
});
}, false, Collections.<Block>emptyList());

if (score > bestScore) {
bestScore = score;
Expand Down