Skip to content
Merged
Changes from all 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 @@ -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;
Expand Down Expand Up @@ -71,10 +72,24 @@ public class AutoEat extends Module {
.build()
);

private final Setting<Boolean> searchInventory = sgGeneral.add(new BoolSetting.Builder()
.name("search-inventory")
.description("Search the full inventory for food, not only the hotbar.")
.defaultValue(false)
.build()
);

private final Setting<Priority> prioritise = sgGeneral.add(new EnumSetting.Builder<Priority>()
.name("food-priority")
.description("Which aspect of the food to prioritise selecting for.")
.defaultValue(Priority.Saturation)
.build()
);

// Threshold
private final Setting<ThresholdMode> thresholdMode = sgThreshold.add(new EnumSetting.Builder<ThresholdMode>()
.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()
);
Expand Down Expand Up @@ -185,7 +200,7 @@ private void startEating() {
}

private void eat() {
changeSlot(slot);
if (!changeSlot(slot)) return;
setPressed(true);
if (!mc.player.isUsingItem()) Utils.rightClick();

Expand Down Expand Up @@ -218,53 +233,93 @@ 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 inventory: move to empty hotbar, abort if none
int emptySlot = InvUtils.find(ItemStack::isEmpty, SlotUtils.HOTBAR_START, SlotUtils.HOTBAR_END).slot();
if (emptySlot == -1) return false;

InvUtils.move().from(slot).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();
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());
}

/**
* Finds the best slot to eat from, preferring:
* offhand => hotbar => main inventory (if allowed).
*/
private int findSlot() {
int slot = -1;
int bestHunger = -1;
// 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);
}

for (int i = 0; i < 9; i++) {
return -1; // nothing found :(
}

private int findBestFood(int start, int end) {
int best = -1;
float bestHunger = -1;

for (int i = 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;
ItemStack stack = mc.player.getInventory().getStack(i);
FoodComponent 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 = foodComponent.nutrition();
float hunger = prioritise.get().value(food);
if (hunger > bestHunger) {
// Skip if item is in blacklist
if (blacklist.get().contains(item)) continue;

// Select the current item
slot = i;
bestHunger = hunger;
best = i;
}
}

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 {
Expand All @@ -283,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();
};
}
}
}