From 2504f5405dde20ba2bc652f297b9572ef249409a Mon Sep 17 00:00:00 2001 From: seb Date: Mon, 27 Apr 2026 23:32:00 +0200 Subject: [PATCH] better messages --- .../sebseb7/autotrade/config/Configs.java | 5 +- .../autotrade/event/AutoTradeClientTick.java | 28 ++++++ .../autotrade/event/ContainerIoHelper.java | 93 +++++++++++++++++-- .../assets/autotrade/lang/en_us.json | 9 +- 4 files changed, 123 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/github/sebseb7/autotrade/config/Configs.java b/src/main/java/com/github/sebseb7/autotrade/config/Configs.java index bd92d50..602386c 100644 --- a/src/main/java/com/github/sebseb7/autotrade/config/Configs.java +++ b/src/main/java/com/github/sebseb7/autotrade/config/Configs.java @@ -24,7 +24,8 @@ public class Configs implements IConfigHandler { "Select buy/sell items with item frames (max. distance 3) with items nametagged \"buy\" or \"sell\""); public static final ConfigBoolean GLASS_BLOCK = new ConfigBoolean("selectUsingGlassBlock", false, "Select input and output containers by placing red (input) and blue (output) stained glass blocks blocks above them (or below if negative)"); - public static final ConfigInteger SELECTOR_OFFSET = new ConfigInteger("selectionBlockOffset", 3, -10, 10, ""); + public static final ConfigInteger SELECTOR_OFFSET = new ConfigInteger("selectionBlockOffset", 3, -10, 10, + "x Blocks below a red stained glass block will be input container, x Blocks below a blue stained glass block will be output container (or above, if x is negative)"); public static final ConfigBoolean ENABLE_SELL = new ConfigBoolean("enableSell", false, "Enable selling (if disabled emeralds are taken from the input container)"); public static final ConfigString SELL_ITEM = new ConfigString("sellItem", "minecraft:gold_ingot", @@ -37,7 +38,7 @@ public class Configs implements IConfigHandler { "The item to buy using emerald. Optional suffix #enc1=lv&enc2=lv matches exact enchantments (use set-buy hotkey with the book in hand)."); public static final ConfigInteger BUY_LIMIT = new ConfigInteger("buyLimit", 64, 1, 64, "max price to buy for"); public static final ConfigInteger MAX_INPUT_ITEMS = new ConfigInteger("maxInputStacks", 9, 1, 35, - "stacks to take from input container (or emerald container in buy-only mode)"); + "stacks to take from input container (or emerald container in buy-only mode), also the max amount of input and emerald kept."); public static final ConfigInteger INPUT_CONTAINER_X = new ConfigInteger("inputContainerX", 0, -30000000, 30000000, "Input container X (not used when sell disabled)"); public static final ConfigInteger INPUT_CONTAINER_Y = new ConfigInteger("inputContainerY", 0, -64, 320, diff --git a/src/main/java/com/github/sebseb7/autotrade/event/AutoTradeClientTick.java b/src/main/java/com/github/sebseb7/autotrade/event/AutoTradeClientTick.java index 782cf0e..8e397c2 100644 --- a/src/main/java/com/github/sebseb7/autotrade/event/AutoTradeClientTick.java +++ b/src/main/java/com/github/sebseb7/autotrade/event/AutoTradeClientTick.java @@ -270,6 +270,8 @@ final class AutoTradeClientTick { menu.setSelectionHint(i); mc.player.connection.send(new ServerboundSelectTradePacket(i)); AutoTrade.bought += offer.getMaxUses(); + InfoUtils.showGuiOrInGameMessage(Message.MessageType.INFO, "autotrade.message.trade_bought", + formatItemCountAndName(offer.getResult()), formatOfferPrice(offer)); try { ContainerIoHelper.quickMoveResultSlot(mc, menu, slot.index); } catch (Exception e) { @@ -283,6 +285,9 @@ final class AutoTradeClientTick { menu.setSelectionHint(i); AutoTrade.sold += offer.getMaxUses(); mc.player.connection.send(new ServerboundSelectTradePacket(i)); + InfoUtils.showGuiOrInGameMessage(Message.MessageType.INFO, "autotrade.message.trade_sold", + formatItemCountAndName(offer.getCostA()) + formatOptionalSecondCost(offer), + formatItemCountAndName(offer.getResult())); try { ContainerIoHelper.quickMoveResultSlot(mc, menu, slot.index); } catch (Exception e) { @@ -293,4 +298,27 @@ final class AutoTradeClientTick { } screen.onClose(); } + + /** e.g. "3× Book" */ + private static String formatItemCountAndName(ItemStack stack) { + return stack.getCount() + "× " + stack.getHoverName().getString(); + } + + /** For buying: the stacks you pay (first + optional second slot). */ + private static String formatOfferPrice(MerchantOffer offer) { + String a = offer.getCostA().isEmpty() ? null : formatItemCountAndName(offer.getCostA()); + if (offer.getCostB().isEmpty()) { + return a != null ? a : "—"; + } + String b = formatItemCountAndName(offer.getCostB()); + return a == null ? b : a + " + " + b; + } + + /** If the trade has a second input item, show it with " + " */ + private static String formatOptionalSecondCost(MerchantOffer offer) { + if (offer.getCostB().isEmpty()) { + return ""; + } + return " + " + formatItemCountAndName(offer.getCostB()); + } } diff --git a/src/main/java/com/github/sebseb7/autotrade/event/ContainerIoHelper.java b/src/main/java/com/github/sebseb7/autotrade/event/ContainerIoHelper.java index 0149300..ebb7398 100644 --- a/src/main/java/com/github/sebseb7/autotrade/event/ContainerIoHelper.java +++ b/src/main/java/com/github/sebseb7/autotrade/event/ContainerIoHelper.java @@ -2,11 +2,14 @@ package com.github.sebseb7.autotrade.event; import com.github.sebseb7.autotrade.config.Configs; import com.github.sebseb7.autotrade.util.TradeItemSpec; +import fi.dy.masa.malilib.gui.Message; +import fi.dy.masa.malilib.util.InfoUtils; import net.minecraft.client.Minecraft; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.ContainerInput; import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.ItemStack; final class ContainerIoHelper { private ContainerIoHelper() { @@ -17,28 +20,38 @@ final class ContainerIoHelper { mc.gameMode.handleContainerInput(menu.containerId, slot.index, 0, ContainerInput.QUICK_MOVE, mc.player); } + private static final String EMERALD_SPEC = "minecraft:emerald"; + static void processOutput(AbstractContainerMenu menu, Inventory playerInv) { - String itemToPlace = "minecraft:emerald"; - if (Configs.Generic.ENABLE_BUY.getBooleanValue()) { - itemToPlace = Configs.Generic.BUY_ITEM.getStringValue(); - } Minecraft mc = Minecraft.getInstance(); - for (int i = 0; i < menu.slots.size(); i++) { - Slot s = menu.getSlot(i); - if (s.container == playerInv) { - if (TradeItemSpec.matches(s.getItem(), itemToPlace)) { + int maxKeep = Configs.Generic.MAX_INPUT_ITEMS.getIntegerValue() * 64; + if (Configs.Generic.ENABLE_BUY.getBooleanValue()) { + String buySpec = Configs.Generic.BUY_ITEM.getStringValue(); + for (int i = 0; i < menu.slots.size(); i++) { + Slot s = menu.getSlot(i); + if (s.container == playerInv && TradeItemSpec.matches(s.getItem(), buySpec)) { + ItemStack stack = s.getItem(); + if (stack.isEmpty()) { + continue; + } try { quickMoveResultSlot(mc, menu, i); + InfoUtils.showGuiOrInGameMessage(Message.MessageType.INFO, + "autotrade.message.moved_bought_to_output", formatStackForMessage(stack)); } catch (Exception e) { System.out.println("err " + e); } } } } + quickMovePlayerExcessOverCap(mc, menu, playerInv, EMERALD_SPEC, maxKeep); + if (Configs.Generic.ENABLE_SELL.getBooleanValue()) { + quickMovePlayerExcessOverCap(mc, menu, playerInv, Configs.Generic.SELL_ITEM.getStringValue(), maxKeep); + } } static void processInput(AbstractContainerMenu menu, Inventory playerInv) { - String itemToTake = "minecraft:emerald"; + String itemToTake = EMERALD_SPEC; if (Configs.Generic.ENABLE_SELL.getBooleanValue()) { itemToTake = Configs.Generic.SELL_ITEM.getStringValue(); } @@ -58,8 +71,14 @@ final class ContainerIoHelper { if (TradeItemSpec.matches(s.getItem(), itemToTake)) { if (inputCount < (Configs.Generic.MAX_INPUT_ITEMS.getIntegerValue() * 64)) { inputCount += s.getItem().getCount(); + ItemStack stack = s.getItem(); + if (stack.isEmpty()) { + continue; + } try { quickMoveResultSlot(mc, menu, i); + InfoUtils.showGuiOrInGameMessage(Message.MessageType.INFO, "autotrade.message.moved_from_input", + formatStackForMessage(stack)); } catch (Exception e) { System.out.println("err " + e); } @@ -67,4 +86,60 @@ final class ContainerIoHelper { } } } + + private static int countMatchingOnPlayer(AbstractContainerMenu menu, Inventory playerInv, String spec) { + int n = 0; + for (int i = 0; i < menu.slots.size(); i++) { + Slot s = menu.getSlot(i); + if (s.container == playerInv && TradeItemSpec.matches(s.getItem(), spec)) { + n += s.getItem().getCount(); + } + } + return n; + } + + /** + * Quick-move player stacks until at most {@code maxKeep} matching items remain + * (same cap as processInput). + */ + private static void quickMovePlayerExcessOverCap(Minecraft mc, AbstractContainerMenu menu, Inventory playerInv, + String spec, int maxKeep) { + while (true) { + int before = countMatchingOnPlayer(menu, playerInv, spec); + if (before <= maxKeep) { + break; + } + boolean moved = false; + for (int i = 0; i < menu.slots.size(); i++) { + Slot s = menu.getSlot(i); + if (s.container != playerInv || !TradeItemSpec.matches(s.getItem(), spec)) { + continue; + } + ItemStack stack = s.getItem(); + if (stack.isEmpty()) { + continue; + } + try { + quickMoveResultSlot(mc, menu, i); + InfoUtils.showGuiOrInGameMessage(Message.MessageType.INFO, + "autotrade.message.moved_excess_to_output", formatStackForMessage(stack)); + } catch (Exception e) { + System.out.println("err " + e); + } + moved = true; + break; + } + if (!moved) { + break; + } + int after = countMatchingOnPlayer(menu, playerInv, spec); + if (after >= before) { + break; + } + } + } + + private static String formatStackForMessage(ItemStack stack) { + return stack.getCount() + "× " + stack.getHoverName().getString(); + } } diff --git a/src/main/resources/assets/autotrade/lang/en_us.json b/src/main/resources/assets/autotrade/lang/en_us.json index 821d7ef..d780493 100644 --- a/src/main/resources/assets/autotrade/lang/en_us.json +++ b/src/main/resources/assets/autotrade/lang/en_us.json @@ -11,5 +11,12 @@ "autotrade.message.sell_item_set": "Item to sell: %s", "autotrade.message.buy_item_set": "Item to buy: %s", "autotrade.message.input_container_set": "Input Container now at: %d %d %d", - "autotrade.message.output_container_set": "Output Container now at: %d %d %d" + "autotrade.message.output_container_set": "Output Container now at: %d %d %d", + + "autotrade.message.trade_bought": "Bought %s (price: %s)", + "autotrade.message.trade_sold": "Sold %s for %s", + + "autotrade.message.moved_bought_to_output": "To output: moved %s from player", + "autotrade.message.moved_excess_to_output": "To output: moved excess %s", + "autotrade.message.moved_from_input": "To inventory: took %s from input" }