diff --git a/gradle.properties b/gradle.properties index 3132730..2916f3e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,12 +6,12 @@ mc_version=1.19.4 yarn_mappings=1.19.4+build.2 loader_version=0.14.19 # Mod Properties -mod_version=1.0.7 +mod_version=1.1.0 maven_group=net.xolt archives_base_name=sbutils # Dependencies # check this on https://modmuss50.me/fabric.html -fabric_version=0.78.0+1.19.4 +fabric_version=0.79.0+1.19.4 modmenu_version=6.2.0 yacl_version=2.4.1 exp4j_version = 0.4.8 diff --git a/src/main/java/net/xolt/sbutils/config/ConfigGui.java b/src/main/java/net/xolt/sbutils/config/ConfigGui.java index 3632e21..f49ef9f 100644 --- a/src/main/java/net/xolt/sbutils/config/ConfigGui.java +++ b/src/main/java/net/xolt/sbutils/config/ConfigGui.java @@ -559,26 +559,26 @@ private static ConfigCategory buildChatLoggerCategory(ModConfig defaults, ModCon .name(Text.translatable("text.sbutils.config.category.chatlogger")) .group(OptionGroup.createBuilder() .name(Text.translatable("text.sbutils.config.group.chatLogger")) - .option(Option.createBuilder(boolean.class) - .name(Text.translatable("text.sbutils.config.option.shopLoggerIncoming")) - .tooltip(Text.translatable("text.sbutils.config.option.shopLoggerIncoming.tooltip")) - .binding( - defaults.shopLoggerIncoming, - () -> config.shopLoggerIncoming, - (value) -> config.shopLoggerIncoming = value - ) - .controller(TickBoxController::new) - .build()) - .option(Option.createBuilder(boolean.class) - .name(Text.translatable("text.sbutils.config.option.shopLoggerOutgoing")) - .tooltip(Text.translatable("text.sbutils.config.option.shopLoggerOutgoing.tooltip")) - .binding( - defaults.shopLoggerOutgoing, - () -> config.shopLoggerOutgoing, - (value) -> config.shopLoggerOutgoing = value - ) - .controller(TickBoxController::new) - .build()) +// .option(Option.createBuilder(boolean.class) +// .name(Text.translatable("text.sbutils.config.option.shopLoggerIncoming")) +// .tooltip(Text.translatable("text.sbutils.config.option.shopLoggerIncoming.tooltip")) +// .binding( +// defaults.shopLoggerIncoming, +// () -> config.shopLoggerIncoming, +// (value) -> config.shopLoggerIncoming = value +// ) +// .controller(TickBoxController::new) +// .build()) +// .option(Option.createBuilder(boolean.class) +// .name(Text.translatable("text.sbutils.config.option.shopLoggerOutgoing")) +// .tooltip(Text.translatable("text.sbutils.config.option.shopLoggerOutgoing.tooltip")) +// .binding( +// defaults.shopLoggerOutgoing, +// () -> config.shopLoggerOutgoing, +// (value) -> config.shopLoggerOutgoing = value +// ) +// .controller(TickBoxController::new) +// .build()) .option(Option.createBuilder(boolean.class) .name(Text.translatable("text.sbutils.config.option.msgLoggerIncoming")) .tooltip(Text.translatable("text.sbutils.config.option.msgLoggerIncoming.tooltip")) @@ -951,6 +951,16 @@ private static ConfigCategory buildAutoSilkCategory(ModConfig defaults, ModConfi ) .controller(TickBoxController::new) .build()) + .option(Option.createBuilder(ModConfig.SilkTarget.class) + .name(Text.translatable("text.sbutils.config.option.targetTool")) + .tooltip(Text.translatable("text.sbutils.config.option.targetTool.tooltip")) + .binding( + defaults.targetTool, + () -> config.targetTool, + (value) -> config.targetTool = value + ) + .controller(EnumController::new) + .build()) .option(Option.createBuilder(double.class) .name(Text.translatable("text.sbutils.config.option.autoSilkDelay")) .tooltip(Text.translatable("text.sbutils.config.option.autoSilkDelay.tooltip")) @@ -990,6 +1000,16 @@ private static ConfigCategory buildAutoCrateCategory(ModConfig defaults, ModConf ) .controller(EnumController::new) .build()) + .option(Option.createBuilder(boolean.class) + .name(Text.translatable("text.sbutils.config.option.doubleSpin")) + .tooltip(Text.translatable("text.sbutils.config.option.doubleSpin.tooltip")) + .binding( + defaults.doubleSpin, + () -> config.doubleSpin, + (value) -> config.doubleSpin = value + ) + .controller(TickBoxController::new) + .build()) .option(Option.createBuilder(double.class) .name(Text.translatable("text.sbutils.config.option.crateDelay")) .tooltip(Text.translatable("text.sbutils.config.option.crateDelay.tooltip")) diff --git a/src/main/java/net/xolt/sbutils/config/ModConfig.java b/src/main/java/net/xolt/sbutils/config/ModConfig.java index f66d22c..1ecccc8 100644 --- a/src/main/java/net/xolt/sbutils/config/ModConfig.java +++ b/src/main/java/net/xolt/sbutils/config/ModConfig.java @@ -3,6 +3,8 @@ import dev.isxander.yacl.api.NameableEnum; import dev.isxander.yacl.config.ConfigEntry; import dev.isxander.yacl.config.ConfigInstance; +import net.minecraft.item.Item; +import net.minecraft.item.Items; import net.minecraft.sound.SoundEvent; import net.minecraft.sound.SoundEvents; import net.minecraft.text.Text; @@ -92,8 +94,8 @@ public class ModConfig { // Chat Logger Settings - @ConfigEntry public boolean shopLoggerIncoming = false; - @ConfigEntry public boolean shopLoggerOutgoing = false; + //@ConfigEntry public boolean shopLoggerIncoming = false; + //@ConfigEntry public boolean shopLoggerOutgoing = false; @ConfigEntry public boolean msgLoggerIncoming = false; @ConfigEntry public boolean msgLoggerOutgoing = false; @ConfigEntry public boolean visitLogger = false; @@ -159,6 +161,7 @@ public class ModConfig { // Auto Silk Settings @ConfigEntry public boolean autoSilk = false; + @ConfigEntry public SilkTarget targetTool = SilkTarget.DIAMOND_PICKAXE; @ConfigEntry public double autoSilkDelay = 0.25; @@ -166,6 +169,7 @@ public class ModConfig { @ConfigEntry public boolean autoCrate = false; @ConfigEntry public CrateMode crateMode = CrateMode.VOTER; + @ConfigEntry public boolean doubleSpin = true; @ConfigEntry public double crateDelay = 0.25; @ConfigEntry public double crateDistance = 4.0; @@ -247,6 +251,28 @@ public Text getDisplayName() { } } + public enum SilkTarget implements NameableEnum { + DIAMOND_PICKAXE(Items.DIAMOND_PICKAXE), + DIAMOND_AXE(Items.DIAMOND_AXE), + DIAMOND_SHOVEL(Items.DIAMOND_SHOVEL), + DIAMOND_HOE(Items.DIAMOND_HOE), + SHEARS(Items.SHEARS); + + private final Item tool; + + SilkTarget(Item tool) { + this.tool = tool; + } + + public Item getTool() { + return tool; + } + + public Text getDisplayName() { + return Text.translatable(tool.getTranslationKey()); + } + } + public enum NotifSound implements NameableEnum, StringIdentifiable { EXPERIENCE(SoundEvents.ENTITY_EXPERIENCE_ORB_PICKUP.getId().toShortTranslationKey(), SoundEvents.ENTITY_EXPERIENCE_ORB_PICKUP), LAY_EGG(SoundEvents.ENTITY_CHICKEN_EGG.getId().toShortTranslationKey(), SoundEvents.ENTITY_CHICKEN_EGG), diff --git a/src/main/java/net/xolt/sbutils/features/AntiPlace.java b/src/main/java/net/xolt/sbutils/features/AntiPlace.java index 1de0212..5c92c84 100644 --- a/src/main/java/net/xolt/sbutils/features/AntiPlace.java +++ b/src/main/java/net/xolt/sbutils/features/AntiPlace.java @@ -5,14 +5,22 @@ import com.mojang.brigadier.tree.LiteralCommandNode; import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Formatting; +import net.minecraft.util.Hand; +import net.minecraft.util.hit.BlockHitResult; import net.xolt.sbutils.config.ModConfig; import net.xolt.sbutils.util.Messenger; import static net.xolt.sbutils.SbUtils.MC; public class AntiPlace { + + private static long lastMessageSentAt; + public static void registerCommand(CommandDispatcher dispatcher) { LiteralCommandNode antiPlaceNode = dispatcher.register(ClientCommandManager.literal("antiplace") .then(ClientCommandManager.literal("heads") @@ -61,31 +69,42 @@ public static void registerCommand(CommandDispatcher .redirect(antiPlaceNode)); } - public static boolean onHandleBlockPlace() { - if (ModConfig.INSTANCE.getConfig().antiPlaceHeads && isHoldingNamedHead()) { + public static boolean shouldCancelBlockInteract(ClientPlayerEntity player, Hand hand, BlockHitResult hitResult) { + if (MC.world == null) { + return false; + } + + ActionResult actionResult = MC.world.getBlockState(hitResult.getBlockPos()).onUse(MC.world, player, hand, hitResult); + if ((actionResult == ActionResult.CONSUME || actionResult == ActionResult.SUCCESS) && !player.isSneaking()) { + return false; + } + + ItemStack held = player.getStackInHand(hand); + if (ModConfig.INSTANCE.getConfig().antiPlaceHeads && isNamedHead(held)) { + notifyBlocked("message.sbutils.antiPlace.headBlocked"); return true; } - if (ModConfig.INSTANCE.getConfig().antiPlaceGrass && isHoldingGrass()) { + + if (ModConfig.INSTANCE.getConfig().antiPlaceGrass && isGrass(held)) { + notifyBlocked("message.sbutils.antiPlace.grassBlocked"); return true; } + return false; } - private static boolean isHoldingNamedHead() { - if (MC.player == null) { - return false; - } + private static boolean isNamedHead(ItemStack item) { + return item.getItem().equals(Items.PLAYER_HEAD) && item.hasCustomName(); + } - ItemStack held = MC.player.getMainHandStack(); - return held.getItem().equals(Items.PLAYER_HEAD) && held.hasCustomName(); + private static boolean isGrass(ItemStack item) { + return item.getItem().equals(Items.GRASS_BLOCK); } - private static boolean isHoldingGrass() { - if (MC.player == null) { - return false; + private static void notifyBlocked(String message) { + if (System.currentTimeMillis() - lastMessageSentAt >= 5000) { + Messenger.printMessage(message, Formatting.RED); + lastMessageSentAt = System.currentTimeMillis(); } - - ItemStack held = MC.player.getMainHandStack(); - return held.getItem().equals(Items.GRASS_BLOCK); } } diff --git a/src/main/java/net/xolt/sbutils/features/AutoAdvert.java b/src/main/java/net/xolt/sbutils/features/AutoAdvert.java index 873f7a8..fa58664 100644 --- a/src/main/java/net/xolt/sbutils/features/AutoAdvert.java +++ b/src/main/java/net/xolt/sbutils/features/AutoAdvert.java @@ -10,6 +10,7 @@ import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; import net.minecraft.client.gui.screen.ProgressScreen; import net.minecraft.text.Text; +import net.minecraft.text.TextColor; import net.minecraft.util.Formatting; import net.xolt.sbutils.config.ModConfig; import net.xolt.sbutils.util.IOHandler; @@ -291,16 +292,24 @@ public static void tick() { adIndex = (adIndex + 1) % prevAdList.size(); } - public static void processTitle(Text title) { - if (RegexFilters.skyblockTitleFilter.matcher(title.getString()).matches()) { - currentServer = SbServer.SKYBLOCK; - prevAdList = getAdList(); - } else if (RegexFilters.economyTitleFilter.matcher(title.getString()).matches()) { - currentServer = SbServer.ECONOMY; - prevAdList = getAdList(); - } else if (RegexFilters.classicTitleFilter.matcher(title.getString()).matches()) { - currentServer = SbServer.CLASSIC; - prevAdList = getAdList(); + public static void processMessage(Text message) { + if (RegexFilters.skyblockJoinFilter.matcher(message.getString()).matches()) { + List siblings = message.getSiblings(); + if (siblings.size() < 1) { + return; + } + + TextColor serverColor = siblings.get(siblings.size() - 1).getStyle().getColor(); + if (serverColor.equals(TextColor.fromFormatting(Formatting.GREEN))) { + currentServer = SbServer.SKYBLOCK; + prevAdList = getAdList(); + } else if (serverColor.equals(TextColor.fromFormatting(Formatting.LIGHT_PURPLE))) { + currentServer = SbServer.ECONOMY; + prevAdList = getAdList(); + } else if (serverColor.equals(TextColor.fromFormatting(Formatting.YELLOW))) { + currentServer = SbServer.CLASSIC; + prevAdList = getAdList(); + } } } diff --git a/src/main/java/net/xolt/sbutils/features/AutoCrate.java b/src/main/java/net/xolt/sbutils/features/AutoCrate.java index 73dab1e..e70326c 100644 --- a/src/main/java/net/xolt/sbutils/features/AutoCrate.java +++ b/src/main/java/net/xolt/sbutils/features/AutoCrate.java @@ -15,6 +15,7 @@ import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtElement; import net.minecraft.nbt.NbtList; +import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket; import net.minecraft.text.MutableText; import net.minecraft.text.Text; import net.minecraft.util.Hand; @@ -230,10 +231,19 @@ private static boolean isItemKey(ItemStack itemStack) { } private static boolean useKey(BlockPos cratePos) { - if (cratePos == null || MC.interactionManager == null) { + if (cratePos == null || MC.interactionManager == null || MC.getNetworkHandler() == null) { return false; } + + if (ModConfig.INSTANCE.getConfig().doubleSpin) { + MC.getNetworkHandler().sendPacket(new ClientCommandC2SPacket(MC.player, ClientCommandC2SPacket.Mode.PRESS_SHIFT_KEY)); + } + MC.interactionManager.interactBlock(MC.player, Hand.MAIN_HAND, new BlockHitResult(cratePos.toCenterPos(), Direction.UP, cratePos, false)); + + if (ModConfig.INSTANCE.getConfig().doubleSpin) { + MC.getNetworkHandler().sendPacket(new ClientCommandC2SPacket(MC.player, ClientCommandC2SPacket.Mode.RELEASE_SHIFT_KEY)); + } return true; } diff --git a/src/main/java/net/xolt/sbutils/features/AutoFix.java b/src/main/java/net/xolt/sbutils/features/AutoFix.java index 2a4736b..945de9a 100644 --- a/src/main/java/net/xolt/sbutils/features/AutoFix.java +++ b/src/main/java/net/xolt/sbutils/features/AutoFix.java @@ -235,7 +235,7 @@ public static void processMessage(Text message) { Matcher fixFailMatcher = RegexFilters.fixFailFilter.matcher(message.getString()); if (fixFailMatcher.matches()) { String minutesText = fixFailMatcher.group(3); - String secondsText = fixFailMatcher.group(5); + String secondsText = fixFailMatcher.group(6); int minutes = minutesText.length() > 0 ? Integer.parseInt(minutesText) : 0; int seconds = secondsText.length() > 0 ? Integer.parseInt(secondsText) : 0; lastActionPerformedAt = calculateLastCommandSentAt((((long)minutes * 60000) + ((long)seconds * 1000) + 2000)); diff --git a/src/main/java/net/xolt/sbutils/features/AutoMine.java b/src/main/java/net/xolt/sbutils/features/AutoMine.java index e1b45f5..4413689 100644 --- a/src/main/java/net/xolt/sbutils/features/AutoMine.java +++ b/src/main/java/net/xolt/sbutils/features/AutoMine.java @@ -116,6 +116,6 @@ private static int getMinDurability() { } public static boolean shouldMine() { - return MC.player != null && !MC.isPaused() && !AutoFix.fixing() && !ToolSaver.shouldCancelAction(); + return MC.player != null && !MC.isPaused() && !AutoFix.fixing() && !ToolSaver.shouldCancelAttack(); } } diff --git a/src/main/java/net/xolt/sbutils/features/AutoRaffle.java b/src/main/java/net/xolt/sbutils/features/AutoRaffle.java index 3afc854..bac0491 100644 --- a/src/main/java/net/xolt/sbutils/features/AutoRaffle.java +++ b/src/main/java/net/xolt/sbutils/features/AutoRaffle.java @@ -21,6 +21,7 @@ public class AutoRaffle { private static boolean enabled; private static boolean waitingToBuy; + private static boolean shouldSendErrorMessage; private static long checkedForGrassAt; public static void registerCommand(CommandDispatcher dispatcher) { @@ -66,7 +67,7 @@ public static void registerCommand(CommandDispatcher public static void tick() { if (enabled != ModConfig.INSTANCE.getConfig().autoRaffle) { enabled = ModConfig.INSTANCE.getConfig().autoRaffle; - waitingToBuy = enabled; + reset(); } if (!ModConfig.INSTANCE.getConfig().autoRaffle || MC.getNetworkHandler() == null || MC.currentScreen instanceof ProgressScreen) { @@ -80,13 +81,13 @@ public static void tick() { public static void processMessage(Text message) { if (ModConfig.INSTANCE.getConfig().autoRaffle && RegexFilters.raffleEndFilter.matcher(message.getString()).matches()) { - waitingToBuy = true; + reset(); } } - public static void onGameJoin() { + public static void onJoinGame() { if (ModConfig.INSTANCE.getConfig().autoRaffle) { - waitingToBuy = true; + reset(); } } @@ -96,15 +97,21 @@ private static void buyTickets() { } int numTickets = Math.min(Math.max(ModConfig.INSTANCE.getConfig().raffleTickets, 1), 2); - if (getGrassCount() < numTickets) { + int grassCount = getGrassCount(); + if (grassCount < 1) { waitingToBuy = true; checkedForGrassAt = System.currentTimeMillis(); + if (shouldSendErrorMessage) { + Messenger.printMessage("message.sbutils.autoRaffle.notEnoughGrass"); + shouldSendErrorMessage = false; + } return; } - MC.getNetworkHandler().sendChatCommand("raffle buy " + numTickets); + int buyAmount = Math.min(numTickets, grassCount); + MC.getNetworkHandler().sendChatCommand("raffle buy " + buyAmount); waitingToBuy = false; - Messenger.printMessage("message.sbutils.autoRaffle.buying"); + Messenger.printWithPlaceholders("message.sbutils.autoRaffle.buying", buyAmount); } private static int getGrassCount() { @@ -123,4 +130,9 @@ private static int getGrassCount() { } return counter; } + + private static void reset() { + waitingToBuy = true; + shouldSendErrorMessage = true; + } } diff --git a/src/main/java/net/xolt/sbutils/features/AutoSilk.java b/src/main/java/net/xolt/sbutils/features/AutoSilk.java index f347f0e..941b69a 100644 --- a/src/main/java/net/xolt/sbutils/features/AutoSilk.java +++ b/src/main/java/net/xolt/sbutils/features/AutoSilk.java @@ -79,8 +79,8 @@ public static void onEnchantUpdate() { return; } - if (state.equals(State.WAIT_FOR_PICK_ENCHANTS)) { - state = State.ENCHANT_PICKAXE; + if (state.equals(State.WAIT_FOR_TOOL_ENCHANTS)) { + state = State.ENCHANT_TOOL; return; } @@ -137,8 +137,9 @@ public static void tick() { reset(); return; } - if (findInEnchantScreen(Items.DIAMOND_PICKAXE, true) == null) { - Messenger.printMessage("message.sbutils.autoSilk.noPickaxes"); + Item targetTool = ModConfig.INSTANCE.getConfig().targetTool.getTool(); + if (findInEnchantScreen(targetTool, true) == null) { + Messenger.printWithPlaceholders("message.sbutils.autoSilk.noTools", targetTool.getTranslationKey()); ModConfig.INSTANCE.getConfig().autoSilk = false; ModConfig.INSTANCE.save(); reset(); @@ -162,10 +163,10 @@ private static void performNextAction() { case INSERT_LAPIS: insertLapis(); break; - case INSERT_PICKAXE: - insertPickaxe(); + case INSERT_TOOL: + insertTool(); break; - case ENCHANT_PICKAXE: + case ENCHANT_TOOL: enchantPickaxe(); break; case RETURN_ITEM_AND_CONTINUE: @@ -187,8 +188,8 @@ private static void insertLapis() { insertItem(Items.LAPIS_LAZULI); } - private static void insertPickaxe() { - insertItem(Items.DIAMOND_PICKAXE); + private static void insertTool() { + insertItem(ModConfig.INSTANCE.getConfig().targetTool.getTool()); } private static void enchantPickaxe() { @@ -230,7 +231,7 @@ private static void insertItem(Item item) { } if (item.equals(Items.LAPIS_LAZULI) && screenHandler.getLapisCount() >= 3) { - state = State.INSERT_PICKAXE; + state = State.INSERT_TOOL; return; } @@ -240,20 +241,20 @@ private static void insertItem(Item item) { return; } - if ((item.equals(Items.BOOK) || item.equals(Items.DIAMOND_PICKAXE)) && !screenHandler.getSlot(0).getStack().isEmpty()) { - // Slot is not empty + if (!item.equals(Items.LAPIS_LAZULI) && !screenHandler.getSlot(0).getStack().isEmpty()) { + // Slot is not empty; remove existing item interactionManager.clickSlot(screenHandler.syncId, 0, 0, SlotActionType.QUICK_MOVE, MC.player); return; } Slot itemSlot = findInEnchantScreen(item, true); if (itemSlot == null) { - if (item.equals(Items.BOOK)) { - Messenger.printMessage("message.sbutils.autoSilk.noBooks"); - } else if (item.equals(Items.DIAMOND_PICKAXE)) { - Messenger.printMessage("message.sbutils.autoSilk.noPickaxes"); - } else if (item.equals(Items.LAPIS_LAZULI)) { + if (item.equals(Items.LAPIS_LAZULI)) { Messenger.printMessage(getTotalLapis() > 0 ? "message.sbutils.autoSilk.notEnoughLapis" : "message.sbutils.autoSilk.noLapis"); + } else if (item.equals(Items.BOOK)) { + Messenger.printMessage("message.sbutils.autoSilk.noBooks"); + } else { + Messenger.printWithPlaceholders("message.sbutils.autoSilk.noTools", item.getTranslationKey()); } reset(); return; @@ -261,16 +262,16 @@ private static void insertItem(Item item) { interactionManager.clickSlot(screenHandler.syncId, itemSlot.id, 0, SlotActionType.QUICK_MOVE, MC.player); - if (item.equals(Items.BOOK)) { - state = State.WAIT_FOR_BOOK_ENCHANTS; - } else if (item.equals(Items.DIAMOND_PICKAXE)) { - state = State.WAIT_FOR_PICK_ENCHANTS; - } else if (item.equals(Items.LAPIS_LAZULI)) { + if (item.equals(Items.LAPIS_LAZULI)) { if (screenHandler.getLapisCount() >= 3) { - state = State.INSERT_PICKAXE; + state = State.INSERT_TOOL; } else { state = State.INSERT_LAPIS; } + } else if (item.equals(Items.BOOK)) { + state = State.WAIT_FOR_BOOK_ENCHANTS; + } else { + state = State.WAIT_FOR_TOOL_ENCHANTS; } } @@ -285,8 +286,6 @@ private static void enchantItem(boolean book) { return; } - - int[] enchantments = screenHandler.enchantmentId; int buttonIndex = book ? 0 : -1; for (int i = 0; i < enchantments.length; i++) { @@ -303,7 +302,7 @@ private static void enchantItem(boolean book) { } if (buttonIndex == -1) { - // No silktouch for pickaxe, continue to book + // No silktouch for tool, continue to book state = State.RETURN_ITEM_AND_CONTINUE; return; } @@ -381,9 +380,9 @@ private static int countFreeSlots() { private enum State { INSERT_LAPIS, - INSERT_PICKAXE, - WAIT_FOR_PICK_ENCHANTS, - ENCHANT_PICKAXE, + INSERT_TOOL, + WAIT_FOR_TOOL_ENCHANTS, + ENCHANT_TOOL, RETURN_ITEM_AND_CONTINUE, INSERT_BOOK, WAIT_FOR_BOOK_ENCHANTS, diff --git a/src/main/java/net/xolt/sbutils/features/ChatLogger.java b/src/main/java/net/xolt/sbutils/features/ChatLogger.java index abc0288..48133b4 100644 --- a/src/main/java/net/xolt/sbutils/features/ChatLogger.java +++ b/src/main/java/net/xolt/sbutils/features/ChatLogger.java @@ -17,14 +17,14 @@ public class ChatLogger { - private static List shopFilters = List.of( - new ChatFilter("text.sbutils.config.option.shopLoggerIncoming", - List.of(RegexFilters.incomingBuyFilter, RegexFilters.incomingSellFilter, RegexFilters.incomingBarterFilter), - () -> ModConfig.INSTANCE.getConfig().shopLoggerIncoming), - new ChatFilter("text.sbutils.config.option.shopLoggerOutgoing", - List.of(RegexFilters.outgoingBuyFilter, RegexFilters.outgoingSellFilter, RegexFilters.outgoingBarterFilter), - () -> ModConfig.INSTANCE.getConfig().shopLoggerOutgoing) - ); +// private static List shopFilters = List.of( +// new ChatFilter("text.sbutils.config.option.shopLoggerIncoming", +// List.of(RegexFilters.incomingBuyFilter, RegexFilters.incomingSellFilter, RegexFilters.incomingBarterFilter), +// () -> ModConfig.INSTANCE.getConfig().shopLoggerIncoming), +// new ChatFilter("text.sbutils.config.option.shopLoggerOutgoing", +// List.of(RegexFilters.outgoingBuyFilter, RegexFilters.outgoingSellFilter, RegexFilters.outgoingBarterFilter), +// () -> ModConfig.INSTANCE.getConfig().shopLoggerOutgoing) +// ); private static List messageFilters = List.of( new ChatFilter("text.sbutils.config.option.msgLoggerIncoming", List.of(RegexFilters.incomingMsgFilter), () -> ModConfig.INSTANCE.getConfig().msgLoggerIncoming), new ChatFilter("text.sbutils.config.option.msgLoggerOutgoing", List.of(RegexFilters.outgoingMsgFilter), () -> ModConfig.INSTANCE.getConfig().msgLoggerOutgoing) @@ -42,44 +42,44 @@ public static void registerCommand(CommandDispatcher Messenger.printEnabledFilters("message.sbutils.chatLogger.status", getFilters()); return Command.SINGLE_SUCCESS; }) - .then(ClientCommandManager.literal("incomingShop") - .executes(context -> { - Messenger.printSetting("text.sbutils.config.option.shopLoggerIncoming", ModConfig.INSTANCE.getConfig().shopLoggerIncoming); - return Command.SINGLE_SUCCESS; - }) - .then(ClientCommandManager.literal("true") - .executes(context -> { - ModConfig.INSTANCE.getConfig().shopLoggerIncoming = true; - ModConfig.INSTANCE.save(); - Messenger.printChangedSetting("text.sbutils.config.option.shopLoggerIncoming", true); - return Command.SINGLE_SUCCESS; - })) - .then(ClientCommandManager.literal("false") - .executes(context -> { - ModConfig.INSTANCE.getConfig().shopLoggerIncoming = false; - ModConfig.INSTANCE.save(); - Messenger.printChangedSetting("text.sbutils.config.option.shopLoggerIncoming", false); - return Command.SINGLE_SUCCESS; - }))) - .then(ClientCommandManager.literal("outgoingShop") - .executes(context -> { - Messenger.printSetting("text.sbutils.config.option.shopLoggerOutgoing", ModConfig.INSTANCE.getConfig().shopLoggerOutgoing); - return Command.SINGLE_SUCCESS; - }) - .then(ClientCommandManager.literal("true") - .executes(context -> { - ModConfig.INSTANCE.getConfig().shopLoggerOutgoing = true; - ModConfig.INSTANCE.save(); - Messenger.printChangedSetting("text.sbutils.config.option.shopLoggerOutgoing", true); - return Command.SINGLE_SUCCESS; - })) - .then(ClientCommandManager.literal("false") - .executes(context -> { - ModConfig.INSTANCE.getConfig().shopLoggerOutgoing = false; - ModConfig.INSTANCE.save(); - Messenger.printChangedSetting("text.sbutils.config.option.shopLoggerOutgoing", false); - return Command.SINGLE_SUCCESS; - }))) +// .then(ClientCommandManager.literal("incomingShop") +// .executes(context -> { +// Messenger.printSetting("text.sbutils.config.option.shopLoggerIncoming", ModConfig.INSTANCE.getConfig().shopLoggerIncoming); +// return Command.SINGLE_SUCCESS; +// }) +// .then(ClientCommandManager.literal("true") +// .executes(context -> { +// ModConfig.INSTANCE.getConfig().shopLoggerIncoming = true; +// ModConfig.INSTANCE.save(); +// Messenger.printChangedSetting("text.sbutils.config.option.shopLoggerIncoming", true); +// return Command.SINGLE_SUCCESS; +// })) +// .then(ClientCommandManager.literal("false") +// .executes(context -> { +// ModConfig.INSTANCE.getConfig().shopLoggerIncoming = false; +// ModConfig.INSTANCE.save(); +// Messenger.printChangedSetting("text.sbutils.config.option.shopLoggerIncoming", false); +// return Command.SINGLE_SUCCESS; +// }))) +// .then(ClientCommandManager.literal("outgoingShop") +// .executes(context -> { +// Messenger.printSetting("text.sbutils.config.option.shopLoggerOutgoing", ModConfig.INSTANCE.getConfig().shopLoggerOutgoing); +// return Command.SINGLE_SUCCESS; +// }) +// .then(ClientCommandManager.literal("true") +// .executes(context -> { +// ModConfig.INSTANCE.getConfig().shopLoggerOutgoing = true; +// ModConfig.INSTANCE.save(); +// Messenger.printChangedSetting("text.sbutils.config.option.shopLoggerOutgoing", true); +// return Command.SINGLE_SUCCESS; +// })) +// .then(ClientCommandManager.literal("false") +// .executes(context -> { +// ModConfig.INSTANCE.getConfig().shopLoggerOutgoing = false; +// ModConfig.INSTANCE.save(); +// Messenger.printChangedSetting("text.sbutils.config.option.shopLoggerOutgoing", false); +// return Command.SINGLE_SUCCESS; +// }))) .then(ClientCommandManager.literal("incomingMsg") .executes(context -> { Messenger.printSetting("text.sbutils.config.option.msgLoggerIncoming", ModConfig.INSTANCE.getConfig().msgLoggerIncoming); @@ -171,11 +171,11 @@ public static void processMessage(Text message) { String stringMessage = message.getString(); long messageReceivedAt = System.currentTimeMillis(); - for (ChatFilter filter : shopFilters) { - if (filter.matches(stringMessage) && filter.isEnabled()) { - IOHandler.logTransaction(message, messageReceivedAt); - } - } +// for (ChatFilter filter : shopFilters) { +// if (filter.matches(stringMessage) && filter.isEnabled()) { +// IOHandler.logTransaction(message, messageReceivedAt); +// } +// } for (ChatFilter filter : messageFilters) { if (filter.matches(stringMessage) && filter.isEnabled()) { @@ -197,11 +197,11 @@ public static void processMessage(Text message) { } private static boolean anyFiltersEnabled() { - for (ChatFilter filter : shopFilters) { - if (filter.isEnabled()) { - return true; - } - } +// for (ChatFilter filter : shopFilters) { +// if (filter.isEnabled()) { +// return true; +// } +// } for (ChatFilter filter : messageFilters) { if (filter.isEnabled()) { @@ -219,7 +219,7 @@ private static boolean anyFiltersEnabled() { public static List getFilters() { List result = new ArrayList<>(); - result.addAll(shopFilters); +// result.addAll(shopFilters); result.addAll(messageFilters); result.addAll(visitFilters); return result; diff --git a/src/main/java/net/xolt/sbutils/features/EnchantAll.java b/src/main/java/net/xolt/sbutils/features/EnchantAll.java index 4c379e3..93fc0df 100644 --- a/src/main/java/net/xolt/sbutils/features/EnchantAll.java +++ b/src/main/java/net/xolt/sbutils/features/EnchantAll.java @@ -383,8 +383,6 @@ private static List getEnchantsForItem(ItemStack itemStack, boolean enchantments.remove(Enchantments.SILK_TOUCH); enchantments.remove(Enchantments.BINDING_CURSE); enchantments.remove(Enchantments.VANISHING_CURSE); - enchantments.remove(Enchantments.SOUL_SPEED); - enchantments.remove(Enchantments.SWIFT_SNEAK); if (ModConfig.INSTANCE.getConfig().excludeFrost && !unenchant) { enchantments.remove(Enchantments.FROST_WALKER); diff --git a/src/main/java/net/xolt/sbutils/features/ToolSaver.java b/src/main/java/net/xolt/sbutils/features/ToolSaver.java index 2f15ae2..19fe7e1 100644 --- a/src/main/java/net/xolt/sbutils/features/ToolSaver.java +++ b/src/main/java/net/xolt/sbutils/features/ToolSaver.java @@ -6,8 +6,21 @@ import com.mojang.brigadier.tree.LiteralCommandNode; import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.entity.Entity; +import net.minecraft.entity.mob.CreeperEntity; +import net.minecraft.entity.passive.MooshroomEntity; +import net.minecraft.entity.passive.SheepEntity; +import net.minecraft.entity.passive.SnowGolemEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.vehicle.TntMinecartEntity; import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemUsageContext; +import net.minecraft.item.Items; +import net.minecraft.util.ActionResult; import net.minecraft.util.Formatting; +import net.minecraft.util.Hand; +import net.minecraft.util.hit.BlockHitResult; import net.xolt.sbutils.config.ModConfig; import net.xolt.sbutils.util.Messenger; @@ -45,35 +58,77 @@ public static void registerCommand(CommandDispatcher .redirect(toolSaverNode)); } - public static boolean onHandleBlockBreaking() { - if (shouldCancelAction()) { - if (System.currentTimeMillis() - lastMessageSentAt >= 5000) { - Messenger.printMessage("message.sbutils.toolSaver.actionBlocked", Formatting.RED); - lastMessageSentAt = System.currentTimeMillis(); - } + public static boolean shouldCancelBlockInteract(ClientPlayerEntity player, Hand hand, BlockHitResult hitResult) { + if (!ModConfig.INSTANCE.getConfig().toolSaver) { + return false; + } + + ItemStack item = player.getStackInHand(hand); + if (!hasLowDurability(item)) { + return false; + } + + ItemUsageContext itemUsageContext = new ItemUsageContext(player, hand, hitResult); + if (item.isDamageable() && item.getItem().useOnBlock(itemUsageContext) != ActionResult.PASS) { + notifyBlocked(); return true; } + return false; } - public static boolean shouldCancelAction() { + public static boolean shouldCancelEntityInteract(PlayerEntity player, Entity entity, Hand hand) { + if (!ModConfig.INSTANCE.getConfig().toolSaver) { + return false; + } + + ItemStack item = player.getStackInHand(hand); + if (!hasLowDurability(item)) { + return false; + } + + if (item.getItem().equals(Items.SHEARS) && + (entity instanceof SheepEntity || entity instanceof MooshroomEntity || entity instanceof SnowGolemEntity)) { + notifyBlocked(); + return true; + } + + if (item.getItem().equals(Items.FLINT_AND_STEEL) && + (entity instanceof CreeperEntity || entity instanceof TntMinecartEntity)) { + notifyBlocked(); + return true; + } + + return false; + } + + public static boolean shouldCancelAttack() { if (!ModConfig.INSTANCE.getConfig().toolSaver || MC.player == null) { return false; } ItemStack holding = MC.player.getMainHandStack(); - if (holding.isEmpty() || !holding.isDamageable()) { - return false; + + if (hasLowDurability(holding)) { + notifyBlocked(); + return true; } - if (holding.getMaxDamage() - holding.getDamage() > ModConfig.INSTANCE.getConfig().toolSaverDurability) { + return false; + } + + private static boolean hasLowDurability(ItemStack item) { + if (item.isEmpty() || !item.isDamageable()) { return false; } - return true; + return item.getMaxDamage() - item.getDamage() <= ModConfig.INSTANCE.getConfig().toolSaverDurability; } - public static void reset() { - lastMessageSentAt = 0; + private static void notifyBlocked() { + if (System.currentTimeMillis() - lastMessageSentAt >= 5000) { + Messenger.printMessage("message.sbutils.toolSaver.actionBlocked", Formatting.RED); + lastMessageSentAt = System.currentTimeMillis(); + } } } diff --git a/src/main/java/net/xolt/sbutils/mixins/ClientConnectionMixin.java b/src/main/java/net/xolt/sbutils/mixins/ClientConnectionMixin.java index 0ae02fb..6080415 100644 --- a/src/main/java/net/xolt/sbutils/mixins/ClientConnectionMixin.java +++ b/src/main/java/net/xolt/sbutils/mixins/ClientConnectionMixin.java @@ -17,7 +17,6 @@ private void onHandleDisconnection(CallbackInfo ci) { EnchantAll.reset(); JoinCommands.reset(); AutoSilk.reset(); - ToolSaver.reset(); AutoFix.reset(); AutoCrate.reset(); diff --git a/src/main/java/net/xolt/sbutils/mixins/ClientPlayNetworkHandlerMixin.java b/src/main/java/net/xolt/sbutils/mixins/ClientPlayNetworkHandlerMixin.java index d5bbe03..7e37fef 100644 --- a/src/main/java/net/xolt/sbutils/mixins/ClientPlayNetworkHandlerMixin.java +++ b/src/main/java/net/xolt/sbutils/mixins/ClientPlayNetworkHandlerMixin.java @@ -6,7 +6,9 @@ import net.minecraft.network.packet.Packet; import net.minecraft.network.packet.c2s.play.ChatMessageC2SPacket; import net.minecraft.network.packet.c2s.play.ClickSlotC2SPacket; +import net.minecraft.network.packet.c2s.play.PlayerInputC2SPacket; import net.minecraft.network.packet.s2c.play.*; +import net.xolt.sbutils.config.ModConfig; import net.xolt.sbutils.features.*; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -27,7 +29,7 @@ public abstract class ClientPlayNetworkHandlerMixin { private void onGameJoin(GameJoinS2CPacket packet, CallbackInfo ci) { JoinCommands.onJoinGame(); AutoAdvert.onJoinGame(); - AutoRaffle.onGameJoin(); + AutoRaffle.onJoinGame(); } @Inject(method = "onCloseScreen", at = @At("HEAD")) @@ -96,11 +98,6 @@ private void onSendPacket(Packet packet, CallbackInfo ci) { } } - @Inject(method = "onTitle", at = @At("HEAD")) - private void onTitle(TitleS2CPacket packet, CallbackInfo ci) { - AutoAdvert.processTitle(packet.getTitle()); - } - @ModifyVariable(method = "sendPacket", at = @At("HEAD"), argsOnly = true) private Packet onSendPacket(Packet packet) { if (packet instanceof ChatMessageC2SPacket) { diff --git a/src/main/java/net/xolt/sbutils/mixins/ClientPlayerInteractionManagerMixin.java b/src/main/java/net/xolt/sbutils/mixins/ClientPlayerInteractionManagerMixin.java index c286a9a..d57ccd9 100644 --- a/src/main/java/net/xolt/sbutils/mixins/ClientPlayerInteractionManagerMixin.java +++ b/src/main/java/net/xolt/sbutils/mixins/ClientPlayerInteractionManagerMixin.java @@ -2,10 +2,14 @@ import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.client.network.ClientPlayerInteractionManager; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.util.ActionResult; import net.minecraft.util.Hand; import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.hit.EntityHitResult; import net.xolt.sbutils.features.AntiPlace; +import net.xolt.sbutils.features.ToolSaver; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -14,11 +18,28 @@ @Mixin(ClientPlayerInteractionManager.class) public class ClientPlayerInteractionManagerMixin { - // Make AntiPlace scaffold-compatible @Inject(method = "interactBlock", at = @At("HEAD"), cancellable = true) private void onInteractBlock(ClientPlayerEntity player, Hand hand, BlockHitResult hitResult, CallbackInfoReturnable cir) { - if (AntiPlace.onHandleBlockPlace()) { - cir.cancel(); + if (ToolSaver.shouldCancelBlockInteract(player, hand, hitResult)) { + cir.setReturnValue(ActionResult.PASS); + } + + if (AntiPlace.shouldCancelBlockInteract(player, hand, hitResult)) { + cir.setReturnValue(ActionResult.PASS); + } + } + + @Inject(method = "interactEntity", at = @At("HEAD"), cancellable = true) + private void onInteractEntity(PlayerEntity player, Entity entity, Hand hand, CallbackInfoReturnable cir) { + if (ToolSaver.shouldCancelEntityInteract(player, entity, hand)) { + cir.setReturnValue(ActionResult.PASS); + } + } + + @Inject(method = "interactEntityAtLocation", at = @At("HEAD"), cancellable = true) + private void onInteractEntityAtLocation(PlayerEntity player, Entity entity, EntityHitResult hitResult, Hand hand, CallbackInfoReturnable cir) { + if (ToolSaver.shouldCancelEntityInteract(player, entity, hand)) { + cir.setReturnValue(ActionResult.PASS); } } } diff --git a/src/main/java/net/xolt/sbutils/mixins/MessageHandlerMixin.java b/src/main/java/net/xolt/sbutils/mixins/MessageHandlerMixin.java index 7c59961..5319039 100644 --- a/src/main/java/net/xolt/sbutils/mixins/MessageHandlerMixin.java +++ b/src/main/java/net/xolt/sbutils/mixins/MessageHandlerMixin.java @@ -55,6 +55,7 @@ private static void preFilterMessage(Text message) { AutoFix.processMessage(message); AutoRaffle.processMessage(message); AutoReply.processMessage(message); + AutoAdvert.processMessage(message); } private static void postFilterMessage(Text message) { diff --git a/src/main/java/net/xolt/sbutils/mixins/MinecraftClientMixin.java b/src/main/java/net/xolt/sbutils/mixins/MinecraftClientMixin.java index 58b8c2b..77a914f 100644 --- a/src/main/java/net/xolt/sbutils/mixins/MinecraftClientMixin.java +++ b/src/main/java/net/xolt/sbutils/mixins/MinecraftClientMixin.java @@ -50,25 +50,15 @@ private void onTickTail(CallbackInfo ci) { @Inject(method = "handleBlockBreaking", at = @At("HEAD"), cancellable = true) public void onHandleBlockBreaking(boolean breaking, CallbackInfo ci) { - if (breaking && ToolSaver.onHandleBlockBreaking()) { + if (breaking && ToolSaver.shouldCancelAttack()) { ci.cancel(); } } @Inject(method = "doAttack", at = @At("HEAD"), cancellable = true) public void onDoAttack(CallbackInfoReturnable cir) { - if (ToolSaver.onHandleBlockBreaking()) { + if (ToolSaver.shouldCancelAttack()) { cir.cancel(); } } - - @Inject(method = "doItemUse", at = @At("HEAD"), cancellable = true) - public void onDoItemUse(CallbackInfo ci) { - if (AntiPlace.onHandleBlockPlace()) { - ci.cancel(); - } - if (ToolSaver.onHandleBlockBreaking()) { - ci.cancel(); - } - } } diff --git a/src/main/java/net/xolt/sbutils/util/IOHandler.java b/src/main/java/net/xolt/sbutils/util/IOHandler.java index b10a289..e8d263e 100644 --- a/src/main/java/net/xolt/sbutils/util/IOHandler.java +++ b/src/main/java/net/xolt/sbutils/util/IOHandler.java @@ -49,7 +49,7 @@ private static boolean createDirectories() { private static boolean createFiles() { try { globalJoinCmdsFile.createNewFile(); - transactionLogFile.createNewFile(); + //transactionLogFile.createNewFile(); messageLogFile.createNewFile(); visitLogFile.createNewFile(); dpLogFile.createNewFile(); diff --git a/src/main/java/net/xolt/sbutils/util/RegexFilters.java b/src/main/java/net/xolt/sbutils/util/RegexFilters.java index e25a41d..28eb17b 100644 --- a/src/main/java/net/xolt/sbutils/util/RegexFilters.java +++ b/src/main/java/net/xolt/sbutils/util/RegexFilters.java @@ -6,9 +6,7 @@ public class RegexFilters { // Auto Advert - public static final Pattern skyblockTitleFilter = Pattern.compile("\u00a7a\u00a7o\u00a7lSkyblock Survival"); - public static final Pattern economyTitleFilter = Pattern.compile("\u00a7d\u00a7o\u00a7lSkyblock Economy"); - public static final Pattern classicTitleFilter = Pattern.compile("\u00a76\u00a7o\u00a7lSkyblock Classic"); + public static final Pattern skyblockJoinFilter = Pattern.compile("Welcome [\u00a7_a-zA-Z0-9]+, to Skyblock!"); // Mentions @@ -49,12 +47,12 @@ public class RegexFilters { // Auto Fix public static final Pattern fixSuccessFilter = Pattern.compile("You have successfully repaired your: .*\\."); - public static final Pattern fixFailFilter = Pattern.compile("You cannot type that command for ((([0-9]+) minutes )?(([0-9]+) seconds)?|now)\\.|Error: This item cannot be repaired\\."); + public static final Pattern fixFailFilter = Pattern.compile("You cannot type that command for ((([0-9]+) (minutes|minute) )?(([0-9]+) (seconds|second))?|now)\\.|Error: This item cannot be repaired\\."); // Auto Raffle - public static final Pattern raffleEndFilter = Pattern.compile("\\[SBRaffle\\] Congratulations go to [\u00a7_a-zA-Z0-9]+ for winning [0-9]+ Grass with [0-9]+ (ticket|tickets)"); + public static final Pattern raffleEndFilter = Pattern.compile("\\[SBRaffle\\] Congratulations go to [\u00a7_a-zA-Z0-9]+ for winning [0-9]+ Grass block with [0-9]+ (ticket|tickets)"); // Auto Crate diff --git a/src/main/resources/assets/sbutils/lang/en_us.json b/src/main/resources/assets/sbutils/lang/en_us.json index 5868064..c25ad63 100644 --- a/src/main/resources/assets/sbutils/lang/en_us.json +++ b/src/main/resources/assets/sbutils/lang/en_us.json @@ -62,10 +62,14 @@ "message.sbutils.toolSaver.actionBlocked": "Action blocked due to item durability being too low.", + "message.sbutils.antiPlace.grassBlocked": "Grass placement blocked.", + "message.sbutils.antiPlace.headBlocked": "Head placement blocked.", + "message.sbutils.autoCommand.infoWithMinutes": "Sending next command in % minutes and % seconds.", "message.sbutils.autoCommand.infoJustSeconds": "Sending next command in % seconds.", - "message.sbutils.autoRaffle.buying": "Buying raffle tickets...", + "message.sbutils.autoRaffle.buying": "Buying @ raffle ticket(s)...", + "message.sbutils.autoRaffle.notEnoughGrass": "You don't have enough grass to purchase raffle tickets.", "message.sbutils.autoPrivate.names": "Current Auto Private names:", "message.sbutils.autoPrivate.nameAddSuccess": "Successfully added the name @ to Auto Private.", @@ -78,7 +82,7 @@ "message.sbutils.autoSilk.invFull": "Disabling Auto Silk because your inventory is full.", "message.sbutils.autoSilk.noLapis": "Disabling Auto Silk because you don't have any lapis in your inventory.", "message.sbutils.autoSilk.notEnoughLapis": "Disabling Auto Silk because you don't have enough lapis in your inventory.", - "message.sbutils.autoSilk.noPickaxes": "Disabling Auto Silk because you don't have any pickaxes in your inventory.", + "message.sbutils.autoSilk.noTools": "Disabling Auto Silk because you don't have any @ in your inventory.", "message.sbutils.autoSilk.noBooks": "Disabling Auto Silk because you don't have any books in your inventory.", "message.sbutils.autoSilk.notEnoughExperience": "Disabling Auto Silk because you don't have enough experience levels.", @@ -369,6 +373,8 @@ "text.sbutils.config.group.autoSilk": "Auto Silk Settings", "text.sbutils.config.option.autoSilk": "Auto Silk Enabled", "text.sbutils.config.option.autoSilk.tooltip": "Automatically enchants books and diamond pickaxes with Silk Touch.", + "text.sbutils.config.option.targetTool": "Target Tool", + "text.sbutils.config.option.targetTool.tooltip": "The tool that Auto Silk will target.", "text.sbutils.config.option.autoSilkDelay": "Auto Silk Delay", "text.sbutils.config.option.autoSilkDelay.tooltip": "The delay between each enchanting action.", @@ -382,6 +388,8 @@ "text.sbutils.config.option.crateMode.voter" : "Voter", "text.sbutils.config.option.crateMode.common" : "Common", "text.sbutils.config.option.crateMode.tooltip": "The type of crate to target.", + "text.sbutils.config.option.doubleSpin": "Double Spin", + "text.sbutils.config.option.doubleSpin.tooltip": "Opens two crate keys at once.", "text.sbutils.config.option.crateDelay": "Crate Delay", "text.sbutils.config.option.crateDelay.tooltip": "After the current crate finishes, how long to wait before opening the next.", "text.sbutils.config.option.crateDistance": "Crate Distance",