diff --git a/src/main/java/baritone/bot/Baritone.java b/src/main/java/baritone/bot/Baritone.java index e13cbade2..96b4e44d1 100755 --- a/src/main/java/baritone/bot/Baritone.java +++ b/src/main/java/baritone/bot/Baritone.java @@ -61,9 +61,11 @@ public enum Baritone { this.inputOverrideHandler = new InputOverrideHandler(); this.settings = new Settings(); this.behaviors = new ArrayList<>(); - behaviors.add(PathingBehavior.INSTANCE); - behaviors.add(LookBehavior.INSTANCE); - behaviors.add(MemoryBehavior.INSTANCE); + { + registerBehavior(PathingBehavior.INSTANCE); + registerBehavior(LookBehavior.INSTANCE); + registerBehavior(MemoryBehavior.INSTANCE); + } this.active = true; this.initialized = true; @@ -87,6 +89,7 @@ public enum Baritone { public void registerBehavior(Behavior behavior) { this.behaviors.add(behavior); + this.gameEventHandler.registerEventListener(behavior); } public final boolean isActive() { diff --git a/src/main/java/baritone/bot/behavior/Behavior.java b/src/main/java/baritone/bot/behavior/Behavior.java index 198dfb8ae..871042462 100644 --- a/src/main/java/baritone/bot/behavior/Behavior.java +++ b/src/main/java/baritone/bot/behavior/Behavior.java @@ -19,6 +19,7 @@ package baritone.bot.behavior; import baritone.bot.event.listener.AbstractGameEventListener; import baritone.bot.utils.Helper; +import baritone.bot.utils.interfaces.Toggleable; /** * A generic bot behavior. @@ -26,7 +27,7 @@ import baritone.bot.utils.Helper; * @author Brady * @since 8/1/2018 6:29 PM */ -public class Behavior implements AbstractGameEventListener, Helper { +public class Behavior implements AbstractGameEventListener, Toggleable, Helper { /** * Whether or not this behavior is enabled @@ -38,6 +39,7 @@ public class Behavior implements AbstractGameEventListener, Helper { * * @return The new state. */ + @Override public final boolean toggle() { return this.setEnabled(!this.enabled); } @@ -47,6 +49,7 @@ public class Behavior implements AbstractGameEventListener, Helper { * * @return The new state. */ + @Override public final boolean setEnabled(boolean enabled) { boolean newState = getNewState(this.enabled, enabled); if (newState == this.enabled) @@ -79,6 +82,7 @@ public class Behavior implements AbstractGameEventListener, Helper { /** * @return Whether or not this {@link Behavior} is active. */ + @Override public final boolean isEnabled() { return this.enabled; } diff --git a/src/main/java/baritone/bot/event/GameEventHandler.java b/src/main/java/baritone/bot/event/GameEventHandler.java index 32bcde8cb..7beeb3d6a 100644 --- a/src/main/java/baritone/bot/event/GameEventHandler.java +++ b/src/main/java/baritone/bot/event/GameEventHandler.java @@ -35,7 +35,6 @@ package baritone.bot.event; import baritone.bot.Baritone; -import baritone.bot.behavior.Behavior; import baritone.bot.chunk.CachedWorld; import baritone.bot.chunk.CachedWorldProvider; import baritone.bot.chunk.ChunkPacker; @@ -44,6 +43,7 @@ import baritone.bot.event.events.type.EventState; import baritone.bot.event.listener.IGameEventListener; import baritone.bot.utils.Helper; import baritone.bot.utils.InputOverrideHandler; +import baritone.bot.utils.interfaces.Toggleable; import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.Tessellator; @@ -51,6 +51,8 @@ import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.client.settings.KeyBinding; import org.lwjgl.input.Keyboard; +import java.util.ArrayList; +import java.util.List; import java.util.function.Consumer; /** @@ -59,18 +61,20 @@ import java.util.function.Consumer; */ public final class GameEventHandler implements IGameEventListener, Helper { + private final List listeners = new ArrayList<>(); + @Override public final void onTick(TickEvent event) { - dispatch(behavior -> behavior.onTick(event)); + dispatch(listener -> listener.onTick(event)); } @Override - public void onPlayerUpdate() { - dispatch(Behavior::onPlayerUpdate); + public final void onPlayerUpdate() { + dispatch(IGameEventListener::onPlayerUpdate); } @Override - public void onProcessKeyBinds() { + public final void onProcessKeyBinds() { InputOverrideHandler inputHandler = Baritone.INSTANCE.getInputOverrideHandler(); // Simulate the key being held down this tick @@ -85,16 +89,16 @@ public final class GameEventHandler implements IGameEventListener, Helper { } } - dispatch(Behavior::onProcessKeyBinds); + dispatch(IGameEventListener::onProcessKeyBinds); } @Override - public void onSendChatMessage(ChatEvent event) { - dispatch(behavior -> behavior.onSendChatMessage(event)); + public final void onSendChatMessage(ChatEvent event) { + dispatch(listener -> listener.onSendChatMessage(event)); } @Override - public void onChunkEvent(ChunkEvent event) { + public final void onChunkEvent(ChunkEvent event) { EventState state = event.getState(); ChunkEvent.Type type = event.getType(); @@ -116,22 +120,22 @@ public final class GameEventHandler implements IGameEventListener, Helper { } } - dispatch(behavior -> behavior.onChunkEvent(event)); + dispatch(listener -> listener.onChunkEvent(event)); } @Override - public void onRenderPass(RenderEvent event) { + public final void onRenderPass(RenderEvent event) { /* CachedWorldProvider.INSTANCE.ifWorldLoaded(world -> world.forEachRegion(region -> region.forEachChunk(chunk -> { drawChunkLine(region.getX() * 512 + chunk.getX() * 16, region.getZ() * 512 + chunk.getZ() * 16, event.getPartialTicks()); }))); */ - dispatch(behavior -> behavior.onRenderPass(event)); + dispatch(listener -> listener.onRenderPass(event)); } @Override - public void onWorldEvent(WorldEvent event) { + public final void onWorldEvent(WorldEvent event) { if (Baritone.settings().chuckCaching.get()) { CachedWorldProvider cache = CachedWorldProvider.INSTANCE; @@ -147,21 +151,34 @@ public final class GameEventHandler implements IGameEventListener, Helper { } } - dispatch(behavior -> behavior.onWorldEvent(event)); + dispatch(listener -> listener.onWorldEvent(event)); } @Override - public void onSendPacket(PacketEvent event) { + public final void onSendPacket(PacketEvent event) { dispatch(behavior -> behavior.onSendPacket(event)); } @Override - public void onReceivePacket(PacketEvent event) { + public final void onReceivePacket(PacketEvent event) { dispatch(behavior -> behavior.onReceivePacket(event)); } - private void dispatch(Consumer dispatchFunction) { - Baritone.INSTANCE.getBehaviors().stream().filter(Behavior::isEnabled).forEach(dispatchFunction); + @Override + public final void onQueryItemSlotForBlocks(ItemSlotEvent event) { + dispatch(behavior -> behavior.onQueryItemSlotForBlocks(event)); + } + + public final void registerEventListener(IGameEventListener listener) { + this.listeners.add(listener); + } + + private void dispatch(Consumer dispatchFunction) { + this.listeners.stream().filter(this::canDispatch).forEach(dispatchFunction); + } + + private boolean canDispatch(IGameEventListener listener) { + return !(listener instanceof Toggleable) || ((Toggleable) listener).isEnabled(); } private void drawChunkLine(int posX, int posZ, float partialTicks) { diff --git a/src/main/java/baritone/bot/event/events/ItemSlotEvent.java b/src/main/java/baritone/bot/event/events/ItemSlotEvent.java new file mode 100644 index 000000000..3362e7808 --- /dev/null +++ b/src/main/java/baritone/bot/event/events/ItemSlotEvent.java @@ -0,0 +1,56 @@ +/* + * 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 . + */ + +package baritone.bot.event.events; + +import baritone.bot.event.listener.IGameEventListener; + +/** + * Called in some cases where a player's inventory has it's current slot queried. + *

+ * @see IGameEventListener#onQueryItemSlotForBlocks() + * + * @author Brady + * @since 8/20/2018 + */ +public final class ItemSlotEvent { + + /** + * The current slot index + */ + private int slot; + + public ItemSlotEvent(int slot) { + this.slot = slot; + } + + /** + * Sets the new slot index that will be used + * + * @param slot The slot index + */ + public final void setSlot(int slot) { + this.slot = slot; + } + + /** + * @return The current slot index + */ + public final int getSlot() { + return this.slot; + } +} diff --git a/src/main/java/baritone/bot/event/listener/AbstractGameEventListener.java b/src/main/java/baritone/bot/event/listener/AbstractGameEventListener.java index 23fd18abf..a3e4251da 100644 --- a/src/main/java/baritone/bot/event/listener/AbstractGameEventListener.java +++ b/src/main/java/baritone/bot/event/listener/AbstractGameEventListener.java @@ -74,4 +74,7 @@ public interface AbstractGameEventListener extends IGameEventListener { @Override default void onReceivePacket(PacketEvent event) {} + + @Override + default void onQueryItemSlotForBlocks(ItemSlotEvent event) {} } diff --git a/src/main/java/baritone/bot/event/listener/IGameEventListener.java b/src/main/java/baritone/bot/event/listener/IGameEventListener.java index d418519d0..d2b0cd28a 100644 --- a/src/main/java/baritone/bot/event/listener/IGameEventListener.java +++ b/src/main/java/baritone/bot/event/listener/IGameEventListener.java @@ -36,11 +36,13 @@ package baritone.bot.event.listener; import baritone.bot.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.multiplayer.WorldClient; import net.minecraft.client.renderer.EntityRenderer; import net.minecraft.client.settings.GameSettings; +import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.network.NetworkManager; import net.minecraft.network.Packet; @@ -114,5 +116,11 @@ 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); } diff --git a/src/main/java/baritone/bot/utils/ToolSet.java b/src/main/java/baritone/bot/utils/ToolSet.java index 575605d11..935e157f4 100644 --- a/src/main/java/baritone/bot/utils/ToolSet.java +++ b/src/main/java/baritone/bot/utils/ToolSet.java @@ -17,6 +17,9 @@ package baritone.bot.utils; +import baritone.bot.Baritone; +import baritone.bot.event.events.ItemSlotEvent; +import baritone.bot.event.listener.AbstractGameEventListener; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; import net.minecraft.client.Minecraft; @@ -36,10 +39,19 @@ import java.util.Map; /** * A cached list of the best tools on the hotbar for any block * - * @author avecowa + * @author avecowa, Brady */ public class ToolSet implements Helper { + /** + * Instance of the internal event listener used to hook into Baritone's event bus + */ + private static final InternalEventListener INTERNAL_EVENT_LISTENER = new InternalEventListener(); + + static { + Baritone.INSTANCE.getGameEventHandler().registerEventListener(INTERNAL_EVENT_LISTENER); + } + /** * 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. @@ -131,18 +143,29 @@ public class ToolSet implements Helper { // Calculate the slot with the best item byte slot = this.getBestSlot(state); - // Save the old current slot - int oldSlot = player().inventory.currentItem; - - // Set the best slot - player().inventory.currentItem = 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 - player().inventory.currentItem = oldSlot; + 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); + } + + public final void setOverrideSlot(int overrideSlot) { + this.overrideSlot = overrideSlot; + } + } } diff --git a/src/main/java/baritone/bot/utils/interfaces/Toggleable.java b/src/main/java/baritone/bot/utils/interfaces/Toggleable.java new file mode 100644 index 000000000..e0d429582 --- /dev/null +++ b/src/main/java/baritone/bot/utils/interfaces/Toggleable.java @@ -0,0 +1,44 @@ +/* + * 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 . + */ + +package baritone.bot.utils.interfaces; + +/** + * @author Brady + * @since 8/20/2018 + */ +public interface Toggleable { + + /** + * Toggles the enabled state of this {@link Toggleable}. + * + * @return The new state. + */ + boolean toggle(); + + /** + * Sets the enabled state of this {@link Toggleable}. + * + * @return The new state. + */ + boolean setEnabled(boolean enabled); + + /** + * @return Whether or not this {@link Toggleable} object is enabled + */ + boolean isEnabled(); +} diff --git a/src/main/java/baritone/launch/mixins/MixinInventoryPlayer.java b/src/main/java/baritone/launch/mixins/MixinInventoryPlayer.java new file mode 100644 index 000000000..8e1b908ba --- /dev/null +++ b/src/main/java/baritone/launch/mixins/MixinInventoryPlayer.java @@ -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 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 . + */ + +package baritone.launch.mixins; + +import baritone.bot.Baritone; +import baritone.bot.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(); + } +} diff --git a/src/main/resources/mixins.baritone.json b/src/main/resources/mixins.baritone.json index 211963471..72f7d4dcc 100755 --- a/src/main/resources/mixins.baritone.json +++ b/src/main/resources/mixins.baritone.json @@ -10,6 +10,7 @@ "MixinGameSettings", "MixinGuiContainer", "MixinGuiScreen", + "MixinInventoryPlayer", "MixinKeyBinding", "MixinMain", "MixinMinecraft",