2525import net .minecraft .component .DataComponentTypes ;
2626import net .minecraft .component .type .FoodComponent ;
2727import net .minecraft .item .Item ;
28+ import net .minecraft .item .ItemStack ;
2829import net .minecraft .item .Items ;
2930
3031import java .util .List ;
@@ -71,10 +72,24 @@ public class AutoEat extends Module {
7172 .build ()
7273 );
7374
75+ private final Setting <Boolean > searchInventory = sgGeneral .add (new BoolSetting .Builder ()
76+ .name ("search-inventory" )
77+ .description ("Search the full inventory for food, not only the hotbar." )
78+ .defaultValue (false )
79+ .build ()
80+ );
81+
82+ private final Setting <Priority > prioritise = sgGeneral .add (new EnumSetting .Builder <Priority >()
83+ .name ("food-priority" )
84+ .description ("Which aspect of the food to prioritise selecting for." )
85+ .defaultValue (Priority .Saturation )
86+ .build ()
87+ );
88+
7489 // Threshold
7590 private final Setting <ThresholdMode > thresholdMode = sgThreshold .add (new EnumSetting .Builder <ThresholdMode >()
7691 .name ("threshold-mode" )
77- .description ("The threshold mode to trigger auto eat." )
92+ .description ("The threshold mode to trigger auto eat.\n 'Both' == health AND hunger, 'Any' == health OR hunger " )
7893 .defaultValue (ThresholdMode .Any )
7994 .build ()
8095 );
@@ -185,7 +200,7 @@ private void startEating() {
185200 }
186201
187202 private void eat () {
188- changeSlot (slot );
203+ if (! changeSlot (slot )) return ;
189204 setPressed (true );
190205 if (!mc .player .isUsingItem ()) Utils .rightClick ();
191206
@@ -218,53 +233,93 @@ private void setPressed(boolean pressed) {
218233 mc .options .useKey .setPressed (pressed );
219234 }
220235
221- private void changeSlot (int slot ) {
222- InvUtils .swap (slot , false );
223- this .slot = slot ;
236+ /**
237+ * Prepares a slot for eating. Uses offhand or hotbar directly.
238+ * Moves a main-inventory item to an empty hotbar slot; returns false if none.
239+ */
240+ private boolean changeSlot (int slot ) {
241+ // offhand: use directly
242+ if (slot == SlotUtils .OFFHAND ) {
243+ this .slot = SlotUtils .OFFHAND ;
244+ return true ;
245+ }
246+
247+ // hotbar: select
248+ if (SlotUtils .isHotbar (slot )) {
249+ InvUtils .swap (slot , false );
250+ this .slot = slot ;
251+ return true ;
252+ }
253+
254+ // main inventory: move to empty hotbar, abort if none
255+ int emptySlot = InvUtils .find (ItemStack ::isEmpty , SlotUtils .HOTBAR_START , SlotUtils .HOTBAR_END ).slot ();
256+ if (emptySlot == -1 ) return false ;
257+
258+ InvUtils .move ().from (slot ).toHotbar (emptySlot );
259+ InvUtils .swap (emptySlot , false );
260+ this .slot = emptySlot ;
261+ return true ;
224262 }
225263
226264 public boolean shouldEat () {
227265 boolean healthLow = mc .player .getHealth () <= healthThreshold .get ();
228266 boolean hungerLow = mc .player .getHungerManager ().getFoodLevel () <= hungerThreshold .get ();
267+ if (!thresholdMode .get ().test (healthLow , hungerLow )) return false ;
268+
229269 slot = findSlot ();
230270 if (slot == -1 ) return false ;
231271
232272 FoodComponent food = mc .player .getInventory ().getStack (slot ).get (DataComponentTypes .FOOD );
233273 if (food == null ) return false ;
234274
235- return thresholdMode .get ().test (healthLow , hungerLow )
236- && (mc .player .getHungerManager ().isNotFull () || food .canAlwaysEat ());
275+ return (mc .player .getHungerManager ().isNotFull () || food .canAlwaysEat ());
237276 }
238277
278+ /**
279+ * Finds the best slot to eat from, preferring:
280+ * offhand => hotbar => main inventory (if allowed).
281+ */
239282 private int findSlot () {
240- int slot = -1 ;
241- int bestHunger = -1 ;
283+ // prefer offhand
284+ Item offHandItem = mc .player .getOffHandStack ().getItem ();
285+ FoodComponent offHandFood = offHandItem .getComponents ().get (DataComponentTypes .FOOD );
286+ if (offHandFood != null && !blacklist .get ().contains (offHandItem )) return SlotUtils .OFFHAND ;
287+
288+ // if offhand empty, prefer best in hotbar
289+ int slot = findBestFood (SlotUtils .HOTBAR_START , SlotUtils .HOTBAR_END );
290+ if (slot != -1 ) return slot ;
291+
292+ // if allowed, search main inventory
293+ if (searchInventory .get ()) {
294+ return findBestFood (SlotUtils .MAIN_START , SlotUtils .MAIN_END );
295+ }
242296
243- for (int i = 0 ; i < 9 ; i ++) {
297+ return -1 ; // nothing found :(
298+ }
299+
300+ private int findBestFood (int start , int end ) {
301+ int best = -1 ;
302+ float bestHunger = -1 ;
303+
304+ for (int i = start ; i <= end ; i ++) {
244305 // Skip if item isn't food
245- Item item = mc .player .getInventory ().getStack (i ).getItem ();
246- FoodComponent foodComponent = item .getComponents ().get (DataComponentTypes .FOOD );
247- if (foodComponent == null ) continue ;
306+ ItemStack stack = mc .player .getInventory ().getStack (i );
307+ FoodComponent food = stack .get (DataComponentTypes .FOOD );
308+ if (food == null ) continue ;
309+
310+ // Skip if item is in blacklist
311+ Item item = stack .getItem ();
312+ if (blacklist .get ().contains (item )) continue ;
248313
249314 // Check if hunger value is better
250- int hunger = foodComponent . nutrition ( );
315+ float hunger = prioritise . get (). value ( food );
251316 if (hunger > bestHunger ) {
252- // Skip if item is in blacklist
253- if (blacklist .get ().contains (item )) continue ;
254-
255- // Select the current item
256- slot = i ;
257317 bestHunger = hunger ;
318+ best = i ;
258319 }
259320 }
260321
261- Item offHandItem = mc .player .getOffHandStack ().getItem ();
262- FoodComponent offHandFood = offHandItem .getComponents ().get (DataComponentTypes .FOOD );
263- if (offHandFood != null && !blacklist .get ().contains (offHandItem ) && offHandFood .nutrition () > bestHunger ) {
264- slot = SlotUtils .OFFHAND ;
265- }
266-
267- return slot ;
322+ return best ;
268323 }
269324
270325 public enum ThresholdMode {
@@ -283,4 +338,18 @@ public boolean test(boolean health, boolean hunger) {
283338 return predicate .test (health , hunger );
284339 }
285340 }
341+
342+ public enum Priority {
343+ Combined ,
344+ Hunger ,
345+ Saturation ;
346+
347+ public float value (FoodComponent food ) {
348+ return switch (this ) {
349+ case Combined -> food .nutrition () + food .saturation ();
350+ case Hunger -> food .nutrition ();
351+ case Saturation -> food .saturation ();
352+ };
353+ }
354+ }
286355}
0 commit comments