Inventory API thing and substitution of legacy code

Also stole `Pair` from elytra branch 😎
This commit is contained in:
Brady 2023-07-04 21:34:57 -07:00
parent 4d7eb003e6
commit 827125d827
No known key found for this signature in database
GPG Key ID: 73A788379A197567
7 changed files with 241 additions and 84 deletions

View File

@ -0,0 +1,42 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Baritone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.api.utils;
import net.minecraft.item.ItemStack;
import java.util.stream.Stream;
/**
* @author Brady
*/
public interface IBaritoneInventory {
/**
* Returns a stream containing all the player's regular inventory slots and items. In the order of hotbar, offhand,
* then main inventory, for a total of 37 slots. This explicitly does not contain the armor slots or crafting grid.
*
* @return All the player's inventory slots and items
*/
Stream<Pair<InventorySlot, ItemStack>> allSlots();
Stream<Pair<InventorySlot, ItemStack>> hotbarSlots();
Stream<Pair<InventorySlot, ItemStack>> inventorySlots();
Pair<InventorySlot, ItemStack> offhand();
}

View File

@ -40,6 +40,8 @@ public interface IPlayerContext {
IPlayerController playerController();
IBaritoneInventory inventory();
World world();
IWorldData worldData();

View File

@ -15,7 +15,7 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.utils;
package baritone.api.utils;
import java.util.function.ObjIntConsumer;

View File

@ -0,0 +1,59 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Baritone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.api.utils;
import java.util.Objects;
/**
* @author Brady
*/
public final class Pair<A, B> {
private final A a;
private final B b;
public Pair(A a, B b) {
this.a = a;
this.b = b;
}
public A first() {
return this.a;
}
public B second() {
return this.b;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || o.getClass() != Pair.class) {
return false;
}
Pair<?, ?> pair = (Pair<?, ?>) o;
return Objects.equals(this.a, pair.a) && Objects.equals(this.b, pair.b);
}
@Override
public int hashCode() {
return 31 * Objects.hashCode(this.a) + Objects.hashCode(this.b);
}
}

View File

@ -20,12 +20,12 @@ package baritone.behavior;
import baritone.Baritone;
import baritone.api.event.events.TickEvent;
import baritone.api.utils.Helper;
import baritone.utils.InventorySlot;
import baritone.api.utils.InventorySlot;
import baritone.api.utils.Pair;
import baritone.utils.ToolSet;
import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.inventory.ClickType;
@ -36,12 +36,10 @@ import net.minecraft.world.World;
import javax.annotation.Nonnull;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Map;
import java.util.OptionalInt;
import java.util.Random;
import java.util.*;
import java.util.function.IntPredicate;
import java.util.function.Predicate;
import java.util.stream.Stream;
public final class InventoryBehavior extends Behavior implements Helper {
@ -69,14 +67,7 @@ public final class InventoryBehavior extends Behavior implements Helper {
}
if (Baritone.settings().allowHotbarManagement.value && baritone.getPathingBehavior().isPathing()) {
// TODO: Some way of indicating which slots are currently reserved by this setting
if (firstValidThrowaway() >= 9) { // aka there are none on the hotbar, but there are some in main inventory
requestSwapWithHotBar(firstValidThrowaway(), 8);
}
int pick = bestToolAgainst(Blocks.STONE, ItemPickaxe.class);
if (pick >= 9) {
requestSwapWithHotBar(pick, 0);
}
this.setupHotbar();
}
if (lastTickRequestedMove != null) {
@ -85,6 +76,22 @@ public final class InventoryBehavior extends Behavior implements Helper {
}
}
private void setupHotbar() {
// TODO: Some way of indicating which slots are currently reserved by this setting
final InventorySlot throwaway = this.findSlotMatching(this::isThrowawayItem);
if (throwaway != null && throwaway.getType() == InventorySlot.Type.INVENTORY) {
// aka there are none on the hotbar, but there are some in main inventory
this.requestSwapWithHotBar(throwaway.getInventoryIndex(), 8);
return;
}
final InventorySlot pick = bestToolAgainst(Blocks.STONE, ItemPickaxe.class);
if (pick != null && pick.getType() == InventorySlot.Type.INVENTORY) {
requestSwapWithHotBar(pick.getInventoryIndex(), 0);
}
}
public boolean attemptToPutOnHotbar(int inMainInvy, IntPredicate disallowedHotbar) {
OptionalInt destination = getTempHotbarSlot(disallowedHotbar);
if (destination.isPresent()) {
@ -132,37 +139,22 @@ public final class InventoryBehavior extends Behavior implements Helper {
return true;
}
private int firstValidThrowaway() { // TODO offhand idk
NonNullList<ItemStack> invy = ctx.player().inventory.mainInventory;
for (int i = 0; i < invy.size(); i++) {
if (this.isThrowawayItem(invy.get(i))) {
return i;
}
}
return -1;
}
private int bestToolAgainst(Block against, Class<? extends ItemTool> cla$$) {
NonNullList<ItemStack> invy = ctx.player().inventory.mainInventory;
int bestInd = -1;
double bestSpeed = -1;
for (int i = 0; i < invy.size(); i++) {
ItemStack stack = invy.get(i);
if (stack.isEmpty()) {
continue;
}
if (Baritone.settings().itemSaver.value && (stack.getItemDamage() + Baritone.settings().itemSaverThreshold.value) >= stack.getMaxDamage() && stack.getMaxDamage() > 1) {
continue;
}
if (cla$$.isInstance(stack.getItem())) {
double speed = ToolSet.calculateSpeedVsBlock(stack, against.getDefaultState()); // takes into account enchants
if (speed > bestSpeed) {
bestSpeed = speed;
bestInd = i;
private InventorySlot bestToolAgainst(final Block against, final Class<? extends ItemTool> cla$$) {
return this.findBestSlotMatching(
Comparator.comparingDouble(stack -> ToolSet.calculateSpeedVsBlock(stack, against.getDefaultState())),
stack -> {
if (stack.isEmpty()) {
return false;
}
if (Baritone.settings().itemSaver.value
&& stack.getItemDamage() + Baritone.settings().itemSaverThreshold.value >= stack.getMaxDamage()
&& stack.getMaxDamage() > 1
) {
return false;
}
return cla$$.isInstance(stack.getItem());
}
}
}
return bestInd;
);
}
public boolean hasGenericThrowaway() {
@ -250,47 +242,40 @@ public final class InventoryBehavior extends Behavior implements Helper {
return null;
}
/**
* Returns an {@link InventorySlot} that contains a stack matching the given predicate. The priority of the
* returned slot is the hotbar, offhand, and finally the main inventory, if {@link #canAccessInventory()} is
* {@code true}. Additionally, for the hotbar and main inventory, slots with a lower index will be returned.
*
* @param desired The predicate to match
* @return A matching slot, or {@code null} if none.
*/
public InventorySlot findSlotMatching(final Predicate<? super ItemStack> desired) {
final InventorySlot hotbar = this.findHotbarMatching(desired);
if (hotbar != null) {
return hotbar;
}
final EntityPlayerSP p = ctx.player();
final NonNullList<ItemStack> inv = p.inventory.mainInventory;
if (desired.test(p.inventory.offHandInventory.get(0))) {
return InventorySlot.offhand();
}
if (this.canAccessInventory()) {
for (int i = 9; i < 36; i++) {
if (desired.test(inv.get(i))) {
return InventorySlot.inventory(i);
}
}
}
return null;
public InventorySlot findSlotMatching(final Predicate<? super ItemStack> filter) {
return this.findBestSlotMatching(null, filter);
}
public InventorySlot findHotbarMatching(final Predicate<? super ItemStack> desired) {
final EntityPlayerSP p = ctx.player();
final NonNullList<ItemStack> inv = p.inventory.mainInventory;
for (int i = 0; i < 9; i++) {
ItemStack item = inv.get(i);
if (desired.test(item)) {
return InventorySlot.hotbar(i);
}
}
return null;
/**
* Returns an {@link InventorySlot} that contains a stack matching the given predicate. A comparator may be
* specified to prioritize slot selection. The comparator may be {@code null}, in which case, the first slot
* matching the predicate is returned. The considered slots are in the order of hotbar, offhand, and finally the
* main inventory (if {@link #canAccessInventory()} is {@code true}).
*
* @param comparator A comparator to find the best element, may be {@code null}
* @param filter The predicate to match
* @return A matching slot, or {@code null} if none.
*/
public InventorySlot findBestSlotMatching(final Comparator<? super ItemStack> comparator, final Predicate<? super ItemStack> filter) {
return this.findBestMatching0(ctx.inventory().allSlots(), comparator, filter);
}
public InventorySlot findHotbarMatching(final Predicate<? super ItemStack> filter) {
return this.findBestHotbarMatching(null, filter);
}
public InventorySlot findBestHotbarMatching(final Comparator<? super ItemStack> comparator, final Predicate<? super ItemStack> filter) {
return this.findBestMatching0(ctx.inventory().hotbarSlots(), comparator, filter);
}
private InventorySlot findBestMatching0(final Stream<Pair<InventorySlot, ItemStack>> slots,
final Comparator<? super ItemStack> comparator,
final Predicate<? super ItemStack> filter) {
final Stream<Pair<InventorySlot, ItemStack>> filtered = slots.filter(slot -> filter.test(slot.second()));
return (comparator != null
? filtered.max((a, b) -> comparator.compare(a.second(), b.second()))
: filtered.findFirst()
).map(Pair::first).orElse(null);
}
public boolean canAccessInventory() {

View File

@ -0,0 +1,62 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Baritone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.utils.player;
import baritone.api.utils.IBaritoneInventory;
import baritone.api.utils.IPlayerContext;
import baritone.api.utils.InventorySlot;
import baritone.api.utils.Pair;
import net.minecraft.item.ItemStack;
import java.util.stream.IntStream;
import java.util.stream.Stream;
/**
* @author Brady
* @since 7/4/2023
*/
public final class BaritoneInventory implements IBaritoneInventory {
private final IPlayerContext ctx;
public BaritoneInventory(IPlayerContext ctx) {
this.ctx = ctx;
}
@Override
public Stream<Pair<InventorySlot, ItemStack>> allSlots() {
return Stream.concat(this.hotbarSlots(), Stream.concat(Stream.of(this.offhand()), this.inventorySlots()));
}
@Override
public Stream<Pair<InventorySlot, ItemStack>> hotbarSlots() {
return IntStream.range(0, 9).mapToObj(i ->
new Pair<>(InventorySlot.hotbar(i), ctx.player().inventory.mainInventory.get(i)));
}
@Override
public Stream<Pair<InventorySlot, ItemStack>> inventorySlots() {
return IntStream.range(9, 36).mapToObj(i ->
new Pair<>(InventorySlot.inventory(i), ctx.player().inventory.mainInventory.get(i)));
}
@Override
public Pair<InventorySlot, ItemStack> offhand() {
return new Pair<>(InventorySlot.offhand(), ctx.player().inventory.offHandInventory.get(0));
}
}

View File

@ -38,11 +38,13 @@ public final class BaritonePlayerContext implements IPlayerContext {
private final Baritone baritone;
private final Minecraft mc;
private final IPlayerController playerController;
private final IBaritoneInventory inventory;
public BaritonePlayerContext(Baritone baritone, Minecraft mc) {
this.baritone = baritone;
this.mc = mc;
this.playerController = new BaritonePlayerController(mc);
this.inventory = new BaritoneInventory(this);
}
@Override
@ -60,6 +62,11 @@ public final class BaritonePlayerContext implements IPlayerContext {
return this.playerController;
}
@Override
public IBaritoneInventory inventory() {
return this.player() == null ? null : this.inventory;
}
@Override
public World world() {
return this.mc.world;