diff --git a/src/api/java/baritone/api/event/events/TickEvent.java b/src/api/java/baritone/api/event/events/TickEvent.java index 5c484ae49..405ad3c49 100644 --- a/src/api/java/baritone/api/event/events/TickEvent.java +++ b/src/api/java/baritone/api/event/events/TickEvent.java @@ -18,9 +18,18 @@ package baritone.api.event.events; import baritone.api.event.events.type.EventState; +import net.minecraft.client.Minecraft; import java.util.function.BiFunction; +/** + * Called on and after each game tick of the primary {@link Minecraft} instance and dispatched to all Baritone + * instances. + *

+ * When {@link #state} is {@link EventState#PRE}, the event is being called just prior to when the current in-game + * screen is ticked. When {@link #state} is {@link EventState#POST}, the event is being called at the very end + * of the {@link Minecraft#runTick()} method. + */ public final class TickEvent { private static int overallTickCount; diff --git a/src/api/java/baritone/api/event/listener/AbstractGameEventListener.java b/src/api/java/baritone/api/event/listener/AbstractGameEventListener.java index 64ae0c16e..54aabe387 100644 --- a/src/api/java/baritone/api/event/listener/AbstractGameEventListener.java +++ b/src/api/java/baritone/api/event/listener/AbstractGameEventListener.java @@ -33,6 +33,9 @@ public interface AbstractGameEventListener extends IGameEventListener { @Override default void onTick(TickEvent event) {} + @Override + default void onPostTick(TickEvent event) {} + @Override default void onPlayerUpdate(PlayerUpdateEvent event) {} diff --git a/src/api/java/baritone/api/event/listener/IGameEventListener.java b/src/api/java/baritone/api/event/listener/IGameEventListener.java index 71e9521ad..22466ce52 100644 --- a/src/api/java/baritone/api/event/listener/IGameEventListener.java +++ b/src/api/java/baritone/api/event/listener/IGameEventListener.java @@ -41,6 +41,14 @@ public interface IGameEventListener { */ void onTick(TickEvent event); + /** + * Run once per game tick after the tick is completed + * + * @param event The event + * @see Minecraft#runTick() + */ + void onPostTick(TickEvent event); + /** * Run once per game tick from before and after the player rotation is sent to the server. * diff --git a/src/launch/java/baritone/launch/mixins/MixinMinecraft.java b/src/launch/java/baritone/launch/mixins/MixinMinecraft.java index ddd17e8d5..13bc2cdf2 100644 --- a/src/launch/java/baritone/launch/mixins/MixinMinecraft.java +++ b/src/launch/java/baritone/launch/mixins/MixinMinecraft.java @@ -35,6 +35,7 @@ import net.minecraft.util.math.BlockPos; import org.spongepowered.asm.lib.Opcodes; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; @@ -53,9 +54,13 @@ public class MixinMinecraft { @Shadow public EntityPlayerSP player; + @Shadow public WorldClient world; + @Unique + private BiFunction tickProvider; + @Inject( method = "init", at = @At("RETURN") @@ -82,18 +87,35 @@ public class MixinMinecraft { ) ) private void runTick(CallbackInfo ci) { - final BiFunction tickProvider = TickEvent.createNextProvider(); + this.tickProvider = TickEvent.createNextProvider(); for (IBaritone baritone : BaritoneAPI.getProvider().getAllBaritones()) { - TickEvent.Type type = baritone.getPlayerContext().player() != null && baritone.getPlayerContext().world() != null ? TickEvent.Type.IN : TickEvent.Type.OUT; - - baritone.getGameEventHandler().onTick(tickProvider.apply(EventState.PRE, type)); + baritone.getGameEventHandler().onTick(this.tickProvider.apply(EventState.PRE, type)); } } + @Inject( + method = "runTick", + at = @At("RETURN") + ) + private void postRunTick() { + if (this.tickProvider == null) { + return; + } + + for (IBaritone baritone : BaritoneAPI.getProvider().getAllBaritones()) { + TickEvent.Type type = baritone.getPlayerContext().player() != null && baritone.getPlayerContext().world() != null + ? TickEvent.Type.IN + : TickEvent.Type.OUT; + baritone.getGameEventHandler().onPostTick(this.tickProvider.apply(EventState.POST, type)); + } + + this.tickProvider = null; + } + @Inject( method = "runTick", at = @At( diff --git a/src/main/java/baritone/event/GameEventHandler.java b/src/main/java/baritone/event/GameEventHandler.java index ceb05e739..d26f2de24 100644 --- a/src/main/java/baritone/event/GameEventHandler.java +++ b/src/main/java/baritone/event/GameEventHandler.java @@ -62,6 +62,11 @@ public final class GameEventHandler implements IEventBus, Helper { listeners.forEach(l -> l.onTick(event)); } + @Override + public void onPostTick(TickEvent event) { + listeners.forEach(l -> l.onPostTick(event)); + } + @Override public final void onPlayerUpdate(PlayerUpdateEvent event) { listeners.forEach(l -> l.onPlayerUpdate(event));