fix tool set once and for all, fixes #136
This commit is contained in:
parent
2cf9a3a74b
commit
de84a49391
@ -1,62 +0,0 @@
|
||||
/*
|
||||
* This file is part of Baritone.
|
||||
*
|
||||
* Baritone is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package baritone.launch.mixins;
|
||||
|
||||
import baritone.Baritone;
|
||||
import baritone.api.event.events.ItemSlotEvent;
|
||||
import net.minecraft.entity.player.InventoryPlayer;
|
||||
import org.spongepowered.asm.lib.Opcodes;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
* @since 8/20/2018
|
||||
*/
|
||||
@Mixin(InventoryPlayer.class)
|
||||
public class MixinInventoryPlayer {
|
||||
|
||||
@Redirect(
|
||||
method = "getDestroySpeed",
|
||||
at = @At(
|
||||
value = "FIELD",
|
||||
opcode = Opcodes.GETFIELD,
|
||||
target = "net/minecraft/entity/player/InventoryPlayer.currentItem:I"
|
||||
)
|
||||
)
|
||||
private int getDestroySpeed$getCurrentItem(InventoryPlayer inventory) {
|
||||
ItemSlotEvent event = new ItemSlotEvent(inventory.currentItem);
|
||||
Baritone.INSTANCE.getGameEventHandler().onQueryItemSlotForBlocks(event);
|
||||
return event.getSlot();
|
||||
}
|
||||
|
||||
@Redirect(
|
||||
method = "canHarvestBlock",
|
||||
at = @At(
|
||||
value = "FIELD",
|
||||
opcode = Opcodes.GETFIELD,
|
||||
target = "net/minecraft/entity/player/InventoryPlayer.currentItem:I"
|
||||
)
|
||||
)
|
||||
private int canHarvestBlock$getCurrentItem(InventoryPlayer inventory) {
|
||||
ItemSlotEvent event = new ItemSlotEvent(inventory.currentItem);
|
||||
Baritone.INSTANCE.getGameEventHandler().onQueryItemSlotForBlocks(event);
|
||||
return event.getSlot();
|
||||
}
|
||||
}
|
@ -17,7 +17,6 @@
|
||||
"MixinGameSettings",
|
||||
"MixinGuiContainer",
|
||||
"MixinGuiScreen",
|
||||
"MixinInventoryPlayer",
|
||||
"MixinKeyBinding",
|
||||
"MixinMinecraft",
|
||||
"MixinNetHandlerPlayClient",
|
||||
|
@ -21,7 +21,6 @@ import baritone.api.event.GameEventHandler;
|
||||
import baritone.behavior.Behavior;
|
||||
import baritone.behavior.impl.*;
|
||||
import baritone.utils.InputOverrideHandler;
|
||||
import baritone.utils.ToolSet;
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
import java.io.File;
|
||||
@ -82,7 +81,6 @@ public enum Baritone {
|
||||
registerBehavior(LocationTrackingBehavior.INSTANCE);
|
||||
registerBehavior(FollowBehavior.INSTANCE);
|
||||
registerBehavior(MineBehavior.INSTANCE);
|
||||
this.gameEventHandler.registerEventListener(ToolSet.INTERNAL_EVENT_LISTENER);
|
||||
}
|
||||
this.dir = new File(Minecraft.getMinecraft().gameDir, "baritone");
|
||||
if (!Files.exists(dir.toPath())) {
|
||||
|
@ -83,6 +83,11 @@ public class Settings {
|
||||
*/
|
||||
public Setting<Boolean> allowWalkOnBottomSlab = new Setting<>(true);
|
||||
|
||||
/**
|
||||
* For example, if you have Mining Fatigue or Haste, adjust the costs of breaking blocks accordingly.
|
||||
*/
|
||||
public Setting<Boolean> considerPotionEffects = new Setting<>(true);
|
||||
|
||||
/**
|
||||
* This is the big A* setting.
|
||||
* As long as your cost heuristic is an *underestimate*, it's guaranteed to find you the best path.
|
||||
|
@ -159,11 +159,6 @@ public final class GameEventHandler implements IGameEventListener, Helper {
|
||||
dispatch(listener -> listener.onReceivePacket(event));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onQueryItemSlotForBlocks(ItemSlotEvent event) {
|
||||
dispatch(listener -> listener.onQueryItemSlotForBlocks(event));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerRelativeMove(RelativeMoveEvent event) {
|
||||
dispatch(listener -> listener.onPlayerRelativeMove(event));
|
||||
|
@ -74,9 +74,6 @@ public interface AbstractGameEventListener extends IGameEventListener {
|
||||
@Override
|
||||
default void onReceivePacket(PacketEvent event) {}
|
||||
|
||||
@Override
|
||||
default void onQueryItemSlotForBlocks(ItemSlotEvent event) {}
|
||||
|
||||
@Override
|
||||
default void onPlayerRelativeMove(RelativeMoveEvent event) {}
|
||||
|
||||
|
@ -36,7 +36,6 @@ package baritone.api.event.listener;
|
||||
|
||||
import baritone.api.event.events.*;
|
||||
import io.netty.util.concurrent.GenericFutureListener;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.entity.EntityPlayerSP;
|
||||
import net.minecraft.client.gui.GuiGameOver;
|
||||
@ -44,7 +43,6 @@ import net.minecraft.client.multiplayer.WorldClient;
|
||||
import net.minecraft.client.renderer.EntityRenderer;
|
||||
import net.minecraft.client.settings.GameSettings;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.InventoryPlayer;
|
||||
import net.minecraft.network.NetworkManager;
|
||||
import net.minecraft.network.Packet;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
@ -120,14 +118,6 @@ public interface IGameEventListener {
|
||||
*/
|
||||
void onReceivePacket(PacketEvent event);
|
||||
|
||||
/**
|
||||
* Run when a query is made for a player's inventory current slot in the context of blocks
|
||||
*
|
||||
* @see InventoryPlayer#getDestroySpeed(IBlockState)
|
||||
* @see InventoryPlayer#canHarvestBlock(IBlockState)
|
||||
*/
|
||||
void onQueryItemSlotForBlocks(ItemSlotEvent event);
|
||||
|
||||
/**
|
||||
* Run once per game tick from before and after the player's moveRelative method is called
|
||||
*
|
||||
|
@ -149,7 +149,7 @@ public abstract class Movement implements Helper, MovementHelper {
|
||||
somethingInTheWay = true;
|
||||
Optional<Rotation> reachable = LookBehaviorUtils.reachable(blockPos);
|
||||
if (reachable.isPresent()) {
|
||||
player().inventory.currentItem = new ToolSet().getBestSlot(BlockStateInterface.get(blockPos));
|
||||
MovementHelper.switchToBestToolFor(BlockStateInterface.get(blockPos));
|
||||
state.setTarget(new MovementState.MovementTarget(reachable.get(), true)).setInput(Input.CLICK_LEFT, true);
|
||||
return false;
|
||||
}
|
||||
|
@ -261,7 +261,7 @@ public interface MovementHelper extends ActionCosts, Helper {
|
||||
return COST_INF;
|
||||
}
|
||||
double m = Blocks.CRAFTING_TABLE.equals(block) ? 10 : 1; // TODO see if this is still necessary. it's from MineBot when we wanted to penalize breaking its crafting table
|
||||
double result = m / context.getToolSet().getStrVsBlock(state, position);
|
||||
double result = m / context.getToolSet().getStrVsBlock(state);
|
||||
if (includeFalling) {
|
||||
BlockPos up = position.up();
|
||||
IBlockState above = BlockStateInterface.get(up);
|
||||
|
@ -17,55 +17,24 @@
|
||||
|
||||
package baritone.utils;
|
||||
|
||||
import baritone.api.event.events.ItemSlotEvent;
|
||||
import baritone.api.event.listener.AbstractGameEventListener;
|
||||
import baritone.Baritone;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.entity.EntityPlayerSP;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemAir;
|
||||
import net.minecraft.enchantment.EnchantmentHelper;
|
||||
import net.minecraft.init.Enchantments;
|
||||
import net.minecraft.init.MobEffects;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.ItemTool;
|
||||
import net.minecraft.util.NonNullList;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A cached list of the best tools on the hotbar for any block
|
||||
*
|
||||
* @author avecowa, Brady
|
||||
* @author avecowa, Brady, leijurv
|
||||
*/
|
||||
public class ToolSet implements Helper {
|
||||
|
||||
/**
|
||||
* Instance of the internal event listener used to hook into Baritone's event bus
|
||||
*/
|
||||
public static final InternalEventListener INTERNAL_EVENT_LISTENER = new InternalEventListener();
|
||||
|
||||
/**
|
||||
* A list of tools on the hotbar that should be considered.
|
||||
* Note that if there are no tools on the hotbar this list will still have one (null) entry.
|
||||
*/
|
||||
private List<ItemTool> tools;
|
||||
|
||||
/**
|
||||
* A mapping from the tools array to what hotbar slots the tool is actually in.
|
||||
* tools.get(i) will be on your hotbar in slot slots.get(i)
|
||||
*/
|
||||
private List<Byte> slots;
|
||||
|
||||
/**
|
||||
* A mapping from a block to which tool index is best for it.
|
||||
* The values in this map are *not* hotbar slots indexes, they need to be looked up in slots
|
||||
* in order to be converted into hotbar slots.
|
||||
*/
|
||||
private Map<Block, Byte> slotCache = new HashMap<>();
|
||||
|
||||
/**
|
||||
* A cache mapping a {@link Block} to how long it will take to break
|
||||
* with this toolset, given the optimum tool is used.
|
||||
@ -75,30 +44,7 @@ public class ToolSet implements Helper {
|
||||
/**
|
||||
* Create a toolset from the current player's inventory (but don't calculate any hardness values just yet)
|
||||
*/
|
||||
public ToolSet() {
|
||||
EntityPlayerSP p = Minecraft.getMinecraft().player;
|
||||
NonNullList<ItemStack> inv = p.inventory.mainInventory;
|
||||
tools = new ArrayList<>();
|
||||
slots = new ArrayList<>();
|
||||
boolean fnull = false;
|
||||
for (byte i = 0; i < 9; i++) {
|
||||
if (!fnull || ((!(inv.get(i).getItem() instanceof ItemAir)) && inv.get(i).getItem() instanceof ItemTool)) {
|
||||
tools.add(inv.get(i).getItem() instanceof ItemTool ? (ItemTool) inv.get(i).getItem() : null);
|
||||
slots.add(i);
|
||||
fnull |= (inv.get(i).getItem() instanceof ItemAir) || (!inv.get(i).getItem().isDamageable());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A caching wrapper around getBestToolIndex
|
||||
*
|
||||
* @param state the blockstate to be mined
|
||||
* @return get which tool on the hotbar is best for mining it
|
||||
*/
|
||||
public Item getBestTool(IBlockState state) {
|
||||
return tools.get(slotCache.computeIfAbsent(state.getBlock(), block -> getBestToolIndex(state)));
|
||||
}
|
||||
public ToolSet() {}
|
||||
|
||||
/**
|
||||
* Calculate which tool on the hotbar is best for mining
|
||||
@ -106,15 +52,11 @@ public class ToolSet implements Helper {
|
||||
* @param b the blockstate to be mined
|
||||
* @return a byte indicating the index in the tools array that worked best
|
||||
*/
|
||||
private byte getBestToolIndex(IBlockState b) {
|
||||
public byte getBestSlot(IBlockState b) {
|
||||
byte best = 0;
|
||||
float value = -1;
|
||||
for (byte i = 0; i < tools.size(); i++) {
|
||||
Item item = tools.get(i);
|
||||
if (item == null)
|
||||
continue;
|
||||
|
||||
float v = item.getDestroySpeed(new ItemStack(item), b);
|
||||
double value = -1;
|
||||
for (byte i = 0; i < 9; i++) {
|
||||
double v = calculateStrVsBlock(i, b);
|
||||
if (v > value || value == -1) {
|
||||
value = v;
|
||||
best = i;
|
||||
@ -123,25 +65,14 @@ public class ToolSet implements Helper {
|
||||
return best;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get which hotbar slot should be selected for fastest mining
|
||||
*
|
||||
* @param state the blockstate to be mined
|
||||
* @return a byte indicating which hotbar slot worked best
|
||||
*/
|
||||
public byte getBestSlot(IBlockState state) {
|
||||
return slots.get(slotCache.computeIfAbsent(state.getBlock(), block -> getBestToolIndex(state)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Using the best tool on the hotbar, how long would it take to mine this block
|
||||
*
|
||||
* @param state the blockstate to be mined
|
||||
* @param pos the blockpos to be mined
|
||||
* @return how long it would take in ticks
|
||||
*/
|
||||
public double getStrVsBlock(IBlockState state, BlockPos pos) {
|
||||
return this.breakStrengthCache.computeIfAbsent(state.getBlock(), b -> calculateStrVsBlock(state, pos));
|
||||
public double getStrVsBlock(IBlockState state) {
|
||||
return this.breakStrengthCache.computeIfAbsent(state.getBlock(), b -> calculateStrVsBlock(getBestSlot(state), state));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -149,36 +80,51 @@ public class ToolSet implements Helper {
|
||||
* in this toolset is used.
|
||||
*
|
||||
* @param state the blockstate to be mined
|
||||
* @param pos the blockpos to be mined
|
||||
* @return how long it would take in ticks
|
||||
*/
|
||||
private double calculateStrVsBlock(IBlockState state, BlockPos pos) {
|
||||
private double calculateStrVsBlock(byte slot, IBlockState state) {
|
||||
// Calculate the slot with the best item
|
||||
byte slot = this.getBestSlot(state);
|
||||
ItemStack contents = player().inventory.getStackInSlot(slot);
|
||||
|
||||
INTERNAL_EVENT_LISTENER.setOverrideSlot(slot);
|
||||
|
||||
// Calculate the relative hardness of the block to the player
|
||||
float hardness = state.getPlayerRelativeBlockHardness(player(), world(), pos);
|
||||
|
||||
// Restore the old slot
|
||||
INTERNAL_EVENT_LISTENER.setOverrideSlot(-1);
|
||||
|
||||
return hardness;
|
||||
}
|
||||
|
||||
private static final class InternalEventListener implements AbstractGameEventListener {
|
||||
|
||||
private int overrideSlot;
|
||||
|
||||
@Override
|
||||
public void onQueryItemSlotForBlocks(ItemSlotEvent event) {
|
||||
if (this.overrideSlot >= 0)
|
||||
event.setSlot(this.overrideSlot);
|
||||
float blockHard = state.getBlockHardness(null, null);
|
||||
if (blockHard < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
final void setOverrideSlot(int overrideSlot) {
|
||||
this.overrideSlot = overrideSlot;
|
||||
float speed = contents.getDestroySpeed(state);
|
||||
if (speed > 1) {
|
||||
int effLevel = EnchantmentHelper.getEnchantmentLevel(Enchantments.EFFICIENCY, contents);
|
||||
if (effLevel > 0 && !contents.isEmpty()) {
|
||||
speed += effLevel * effLevel + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (Baritone.settings().considerPotionEffects.get()) {
|
||||
if (player().isPotionActive(MobEffects.HASTE)) {
|
||||
speed *= 1 + (player().getActivePotionEffect(MobEffects.HASTE).getAmplifier() + 1) * 0.2;
|
||||
}
|
||||
if (player().isPotionActive(MobEffects.MINING_FATIGUE)) {
|
||||
switch (player().getActivePotionEffect(MobEffects.MINING_FATIGUE).getAmplifier()) {
|
||||
case 0:
|
||||
speed *= 0.3;
|
||||
break;
|
||||
case 1:
|
||||
speed *= 0.09;
|
||||
break;
|
||||
case 2:
|
||||
speed *= 0.0027;
|
||||
break;
|
||||
default:
|
||||
speed *= 0.00081;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
speed /= blockHard;
|
||||
if (state.getMaterial().isToolNotRequired() || (!contents.isEmpty() && contents.canHarvestBlock(state))) {
|
||||
return speed / 30;
|
||||
} else {
|
||||
return speed / 100;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user