From 0dea8ad7655ef3b13d086e8831272530c8a2a124 Mon Sep 17 00:00:00 2001 From: uxmlen <38371923+uxmlen@users.noreply.github.com> Date: Sun, 11 Jan 2026 13:46:51 +0300 Subject: [PATCH 1/5] Add search-inventory option to AutoEat Add boolean `search-inventory` (default: false). Previously, AutoEat only searched the hotbar for food. With this option enabled, it scans both the hotbar and main inventory. Food from the main inventory is moved to an empty hotbar slot before use (only if the hotbar has a free slot). --- .../systems/modules/player/AutoEat.java | 52 ++++++++++++++++--- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/player/AutoEat.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/player/AutoEat.java index 8640666fd1..4ad008c318 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/player/AutoEat.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/player/AutoEat.java @@ -25,6 +25,7 @@ import net.minecraft.component.DataComponentTypes; import net.minecraft.component.type.FoodComponent; import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import java.util.List; @@ -71,6 +72,13 @@ public class AutoEat extends Module { .build() ); + private final Setting searchInventory = sgGeneral.add(new BoolSetting.Builder() + .name("search-inventory") + .description("Search the full inventory for food, not only the hotbar.") + .defaultValue(false) + .build() + ); + // Threshold private final Setting thresholdMode = sgThreshold.add(new EnumSetting.Builder() .name("threshold-mode") @@ -185,7 +193,7 @@ private void startEating() { } private void eat() { - changeSlot(slot); + if (!changeSlot(slot)) return; setPressed(true); if (!mc.player.isUsingItem()) Utils.rightClick(); @@ -218,11 +226,35 @@ private void setPressed(boolean pressed) { mc.options.useKey.setPressed(pressed); } - private void changeSlot(int slot) { - InvUtils.swap(slot, false); - this.slot = slot; + /** + * Prepares a slot for eating. Uses offhand or hotbar directly. + * Moves a main-inventory item to an empty hotbar slot; returns false if none. + */ + private boolean changeSlot(int slot) { + // offhand: use directly + if (slot == SlotUtils.OFFHAND) { + this.slot = SlotUtils.OFFHAND; + return true; + } + + // hotbar: select + if (SlotUtils.isHotbar(slot)) { + InvUtils.swap(slot, false); + this.slot = slot; + return true; + } + + // main: move to empty hotbar, abort if none + var hotbarIndex = InvUtils.find(ItemStack::isEmpty, SlotUtils.HOTBAR_START, SlotUtils.HOTBAR_END).slot(); + if (hotbarIndex == -1) return false; + + InvUtils.move().fromMain(slot - SlotUtils.MAIN_START).toHotbar(hotbarIndex); + InvUtils.swap(hotbarIndex, false); + this.slot = hotbarIndex; + return true; } + public boolean shouldEat() { boolean healthLow = mc.player.getHealth() <= healthThreshold.get(); boolean hungerLow = mc.player.getHungerManager().getFoodLevel() <= hungerThreshold.get(); @@ -240,24 +272,28 @@ private int findSlot() { int slot = -1; int bestHunger = -1; - for (int i = 0; i < 9; i++) { + // search hotbar only, or hotbar + inventory if enabled + int end = searchInventory.get() ? SlotUtils.MAIN_END : SlotUtils.HOTBAR_END; + + for (int i = SlotUtils.HOTBAR_START; i <= end; i++) { // Skip if item isn't food Item item = mc.player.getInventory().getStack(i).getItem(); FoodComponent foodComponent = item.getComponents().get(DataComponentTypes.FOOD); if (foodComponent == null) continue; + // Skip if item is in blacklist + if (blacklist.get().contains(item)) continue; + // Check if hunger value is better int hunger = foodComponent.nutrition(); if (hunger > bestHunger) { - // Skip if item is in blacklist - if (blacklist.get().contains(item)) continue; - // Select the current item slot = i; bestHunger = hunger; } } + // Offhand check Item offHandItem = mc.player.getOffHandStack().getItem(); FoodComponent offHandFood = offHandItem.getComponents().get(DataComponentTypes.FOOD); if (offHandFood != null && !blacklist.get().contains(offHandItem) && offHandFood.nutrition() > bestHunger) { From ef8c8f601423569efa7f30169cdf5e3d9a7ae3f4 Mon Sep 17 00:00:00 2001 From: uxmlen <38371923+uxmlen@users.noreply.github.com> Date: Sun, 11 Jan 2026 16:05:14 +0300 Subject: [PATCH 2/5] fix: prefer hotbar before inventory 1. find best food in hotbar 2. if nothing found, check offhand 3. if allowed, search main inventory --- .../systems/modules/player/AutoEat.java | 65 ++++++++++--------- 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/player/AutoEat.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/player/AutoEat.java index 4ad008c318..88ad5c25e3 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/player/AutoEat.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/player/AutoEat.java @@ -244,17 +244,16 @@ private boolean changeSlot(int slot) { return true; } - // main: move to empty hotbar, abort if none - var hotbarIndex = InvUtils.find(ItemStack::isEmpty, SlotUtils.HOTBAR_START, SlotUtils.HOTBAR_END).slot(); - if (hotbarIndex == -1) return false; + // main inventory move to empty hotbar, abort if none + var emptySlot = InvUtils.find(ItemStack::isEmpty, SlotUtils.HOTBAR_START, SlotUtils.HOTBAR_END).slot(); + if (emptySlot == -1) return false; - InvUtils.move().fromMain(slot - SlotUtils.MAIN_START).toHotbar(hotbarIndex); - InvUtils.swap(hotbarIndex, false); - this.slot = hotbarIndex; + InvUtils.move().fromMain(slot - SlotUtils.MAIN_START).toHotbar(emptySlot); + InvUtils.swap(emptySlot, false); + this.slot = emptySlot; return true; } - public boolean shouldEat() { boolean healthLow = mc.player.getHealth() <= healthThreshold.get(); boolean hungerLow = mc.player.getHungerManager().getFoodLevel() <= hungerThreshold.get(); @@ -265,44 +264,50 @@ public boolean shouldEat() { if (food == null) return false; return thresholdMode.get().test(healthLow, hungerLow) - && (mc.player.getHungerManager().isNotFull() || food.canAlwaysEat()); + && (mc.player.getHungerManager().isNotFull() || food.canAlwaysEat()); } private int findSlot() { - int slot = -1; - int bestHunger = -1; + // prefer best in hotbar + int slot = findBestInRange(SlotUtils.HOTBAR_START, SlotUtils.HOTBAR_END); + if (slot != -1) return slot; + + // if hotbar empty, prefer offhand + Item offHandItem = mc.player.getOffHandStack().getItem(); + FoodComponent offHandFood = offHandItem.getComponents().get(DataComponentTypes.FOOD); + if (offHandFood != null && !blacklist.get().contains(offHandItem)) return SlotUtils.OFFHAND; - // search hotbar only, or hotbar + inventory if enabled - int end = searchInventory.get() ? SlotUtils.MAIN_END : SlotUtils.HOTBAR_END; + // if allowed, search main inventory + if (searchInventory.get()) { + return findBestInRange(SlotUtils.MAIN_START, SlotUtils.MAIN_END); + } - for (int i = SlotUtils.HOTBAR_START; i <= end; i++) { - // Skip if item isn't food - Item item = mc.player.getInventory().getStack(i).getItem(); - FoodComponent foodComponent = item.getComponents().get(DataComponentTypes.FOOD); - if (foodComponent == null) continue; + return -1; // nothing found + } - // Skip if item is in blacklist + private int findBestInRange(int start, int end) { + int best = -1; + int bestHunger = -1; + + for (int i = start; i <= end; i++) { + var stack = mc.player.getInventory().getStack(i); + var food = stack.get(DataComponentTypes.FOOD); + if (food == null) continue; + + Item item = stack.getItem(); if (blacklist.get().contains(item)) continue; - // Check if hunger value is better - int hunger = foodComponent.nutrition(); + int hunger = food.nutrition(); if (hunger > bestHunger) { - // Select the current item - slot = i; bestHunger = hunger; + best = i; } } - // Offhand check - Item offHandItem = mc.player.getOffHandStack().getItem(); - FoodComponent offHandFood = offHandItem.getComponents().get(DataComponentTypes.FOOD); - if (offHandFood != null && !blacklist.get().contains(offHandItem) && offHandFood.nutrition() > bestHunger) { - slot = SlotUtils.OFFHAND; - } - - return slot; + return best; } + public enum ThresholdMode { Health((health, hunger) -> health), Hunger((health, hunger) -> hunger), From 6100f72cf6cfb5c46e707f35877e0f370f95c294 Mon Sep 17 00:00:00 2001 From: uxmlen <38371923+uxmlen@users.noreply.github.com> Date: Sun, 11 Jan 2026 16:16:24 +0300 Subject: [PATCH 3/5] refactor: rename methods + improve comments --- .../systems/modules/player/AutoEat.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/player/AutoEat.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/player/AutoEat.java index 88ad5c25e3..c2b1a07b04 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/player/AutoEat.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/player/AutoEat.java @@ -244,7 +244,7 @@ private boolean changeSlot(int slot) { return true; } - // main inventory move to empty hotbar, abort if none + // main inventory: move to empty hotbar, abort if none var emptySlot = InvUtils.find(ItemStack::isEmpty, SlotUtils.HOTBAR_START, SlotUtils.HOTBAR_END).slot(); if (emptySlot == -1) return false; @@ -267,9 +267,13 @@ public boolean shouldEat() { && (mc.player.getHungerManager().isNotFull() || food.canAlwaysEat()); } + /** + * Finds the best slot to eat from, preferring: + * hotbar => offhand => main inventory (if allowed). + */ private int findSlot() { // prefer best in hotbar - int slot = findBestInRange(SlotUtils.HOTBAR_START, SlotUtils.HOTBAR_END); + int slot = findBestFood(SlotUtils.HOTBAR_START, SlotUtils.HOTBAR_END); if (slot != -1) return slot; // if hotbar empty, prefer offhand @@ -279,24 +283,27 @@ private int findSlot() { // if allowed, search main inventory if (searchInventory.get()) { - return findBestInRange(SlotUtils.MAIN_START, SlotUtils.MAIN_END); + return findBestFood(SlotUtils.MAIN_START, SlotUtils.MAIN_END); } - return -1; // nothing found + return -1; // nothing found :( } - private int findBestInRange(int start, int end) { + private int findBestFood(int start, int end) { int best = -1; int bestHunger = -1; for (int i = start; i <= end; i++) { + // Skip if item isn't food var stack = mc.player.getInventory().getStack(i); var food = stack.get(DataComponentTypes.FOOD); if (food == null) continue; + // Skip if item is in blacklist Item item = stack.getItem(); if (blacklist.get().contains(item)) continue; + // Check if hunger value is better int hunger = food.nutrition(); if (hunger > bestHunger) { bestHunger = hunger; @@ -307,7 +314,6 @@ private int findBestInRange(int start, int end) { return best; } - public enum ThresholdMode { Health((health, hunger) -> health), Hunger((health, hunger) -> hunger), From 7d5c1a81d301e64c350ebb4f770e07b37dd5c8b6 Mon Sep 17 00:00:00 2001 From: uxmlen <38371923+uxmlen@users.noreply.github.com> Date: Sun, 11 Jan 2026 16:35:27 +0300 Subject: [PATCH 4/5] change food slot priority: offhand => hotbar => inventory --- .../meteorclient/systems/modules/player/AutoEat.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/player/AutoEat.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/player/AutoEat.java index c2b1a07b04..764e701ad2 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/player/AutoEat.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/player/AutoEat.java @@ -269,18 +269,18 @@ public boolean shouldEat() { /** * Finds the best slot to eat from, preferring: - * hotbar => offhand => main inventory (if allowed). + * offhand => hotbar => main inventory (if allowed). */ private int findSlot() { - // prefer best in hotbar - int slot = findBestFood(SlotUtils.HOTBAR_START, SlotUtils.HOTBAR_END); - if (slot != -1) return slot; - - // if hotbar empty, prefer offhand + // prefer offhand Item offHandItem = mc.player.getOffHandStack().getItem(); FoodComponent offHandFood = offHandItem.getComponents().get(DataComponentTypes.FOOD); if (offHandFood != null && !blacklist.get().contains(offHandItem)) return SlotUtils.OFFHAND; + // if offhand empty, prefer best in hotbar + int slot = findBestFood(SlotUtils.HOTBAR_START, SlotUtils.HOTBAR_END); + if (slot != -1) return slot; + // if allowed, search main inventory if (searchInventory.get()) { return findBestFood(SlotUtils.MAIN_START, SlotUtils.MAIN_END); From f3e7082205df4aaa5a53325d9d8ce8e1a90bf706 Mon Sep 17 00:00:00 2001 From: Wide_Cat Date: Mon, 12 Jan 2026 17:04:25 +0000 Subject: [PATCH 5/5] some refactors --- .../systems/modules/player/AutoEat.java | 40 ++++++++++++++----- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/player/AutoEat.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/player/AutoEat.java index 764e701ad2..12b8d8e313 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/player/AutoEat.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/player/AutoEat.java @@ -79,10 +79,17 @@ public class AutoEat extends Module { .build() ); + private final Setting prioritise = sgGeneral.add(new EnumSetting.Builder() + .name("food-priority") + .description("Which aspect of the food to prioritise selecting for.") + .defaultValue(Priority.Saturation) + .build() + ); + // Threshold private final Setting thresholdMode = sgThreshold.add(new EnumSetting.Builder() .name("threshold-mode") - .description("The threshold mode to trigger auto eat.") + .description("The threshold mode to trigger auto eat.\n'Both' == health AND hunger, 'Any' == health OR hunger") .defaultValue(ThresholdMode.Any) .build() ); @@ -245,10 +252,10 @@ private boolean changeSlot(int slot) { } // main inventory: move to empty hotbar, abort if none - var emptySlot = InvUtils.find(ItemStack::isEmpty, SlotUtils.HOTBAR_START, SlotUtils.HOTBAR_END).slot(); + int emptySlot = InvUtils.find(ItemStack::isEmpty, SlotUtils.HOTBAR_START, SlotUtils.HOTBAR_END).slot(); if (emptySlot == -1) return false; - InvUtils.move().fromMain(slot - SlotUtils.MAIN_START).toHotbar(emptySlot); + InvUtils.move().from(slot).toHotbar(emptySlot); InvUtils.swap(emptySlot, false); this.slot = emptySlot; return true; @@ -257,14 +264,15 @@ private boolean changeSlot(int slot) { public boolean shouldEat() { boolean healthLow = mc.player.getHealth() <= healthThreshold.get(); boolean hungerLow = mc.player.getHungerManager().getFoodLevel() <= hungerThreshold.get(); + if (!thresholdMode.get().test(healthLow, hungerLow)) return false; + slot = findSlot(); if (slot == -1) return false; FoodComponent food = mc.player.getInventory().getStack(slot).get(DataComponentTypes.FOOD); if (food == null) return false; - return thresholdMode.get().test(healthLow, hungerLow) - && (mc.player.getHungerManager().isNotFull() || food.canAlwaysEat()); + return (mc.player.getHungerManager().isNotFull() || food.canAlwaysEat()); } /** @@ -291,12 +299,12 @@ private int findSlot() { private int findBestFood(int start, int end) { int best = -1; - int bestHunger = -1; + float bestHunger = -1; for (int i = start; i <= end; i++) { // Skip if item isn't food - var stack = mc.player.getInventory().getStack(i); - var food = stack.get(DataComponentTypes.FOOD); + ItemStack stack = mc.player.getInventory().getStack(i); + FoodComponent food = stack.get(DataComponentTypes.FOOD); if (food == null) continue; // Skip if item is in blacklist @@ -304,7 +312,7 @@ private int findBestFood(int start, int end) { if (blacklist.get().contains(item)) continue; // Check if hunger value is better - int hunger = food.nutrition(); + float hunger = prioritise.get().value(food); if (hunger > bestHunger) { bestHunger = hunger; best = i; @@ -330,4 +338,18 @@ public boolean test(boolean health, boolean hunger) { return predicate.test(health, hunger); } } + + public enum Priority { + Combined, + Hunger, + Saturation; + + public float value(FoodComponent food) { + return switch (this) { + case Combined -> food.nutrition() + food.saturation(); + case Hunger -> food.nutrition(); + case Saturation -> food.saturation(); + }; + } + } }