diff --git a/src/api/java/baritone/api/event/listener/IEventBus.java b/src/api/java/baritone/api/event/listener/IEventBus.java
index 52240a7c0..78118f5f8 100644
--- a/src/api/java/baritone/api/event/listener/IEventBus.java
+++ b/src/api/java/baritone/api/event/listener/IEventBus.java
@@ -21,6 +21,8 @@
* A type of {@link IGameEventListener} that can have additional listeners
* registered so that they receive the events that are dispatched to this
* listener.
+ *
+ * Listeners with higher priority will be called first.
*
* @author Brady
* @since 11/14/2018
@@ -29,8 +31,17 @@ public interface IEventBus extends IGameEventListener {
/**
* Registers the specified {@link IGameEventListener} to this event bus
+ * using a default priority {@code 0}
*
* @param listener The listener
*/
void registerEventListener(IGameEventListener listener);
+
+ /**
+ * Registers the specified {@link IGameEventListener} to this event bus.
+ *
+ * @param priority The listener priority
+ * @param listener The listener
+ */
+ void registerEventListener(int priority, IGameEventListener listener);
}
diff --git a/src/main/java/baritone/event/GameEventHandler.java b/src/main/java/baritone/event/GameEventHandler.java
index d716ff849..40ebb3ac4 100644
--- a/src/main/java/baritone/event/GameEventHandler.java
+++ b/src/main/java/baritone/event/GameEventHandler.java
@@ -27,6 +27,8 @@
import baritone.cache.CachedChunk;
import baritone.cache.WorldProvider;
import baritone.utils.BlockStateInterface;
+import it.unimi.dsi.fastutil.ints.IntList;
+import it.unimi.dsi.fastutil.ints.IntArrayList;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
@@ -43,7 +45,9 @@ public final class GameEventHandler implements IEventBus, Helper {
private final Baritone baritone;
+ // reading/iterating `listeners` is allowed without synchronization
private final List listeners = new CopyOnWriteArrayList<>();
+ private final IntList priorities = new IntArrayList();
public GameEventHandler(Baritone baritone) {
this.baritone = baritone;
@@ -184,6 +188,16 @@ public void onPathEvent(PathEvent event) {
@Override
public final void registerEventListener(IGameEventListener listener) {
- this.listeners.add(listener);
+ this.registerEventListener(0, listener);
+ }
+
+ @Override
+ public final synchronized void registerEventListener(int priority, IGameEventListener listener) {
+ int i = 0;
+ while (i < this.listeners.size() && priority <= this.priorities.getInt(i)) {
+ ++i;
+ }
+ this.listeners.add(i, listener);
+ this.priorities.add(i, priority);
}
}
diff --git a/src/test/java/baritone/event/GameEventHandlerTest.java b/src/test/java/baritone/event/GameEventHandlerTest.java
new file mode 100644
index 000000000..04788c727
--- /dev/null
+++ b/src/test/java/baritone/event/GameEventHandlerTest.java
@@ -0,0 +1,68 @@
+/*
+ * 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 .
+ */
+
+package baritone.event;
+
+import baritone.api.event.listener.AbstractGameEventListener;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+public class GameEventHandlerTest {
+
+ @Test
+ public void testListenerOrder() {
+ GameEventHandler bus = new GameEventHandler(null /* baritone */);
+
+ List output = new ArrayList<>();
+
+ bus.registerEventListener(0, new TestEventListener("0 0", output));
+ bus.registerEventListener(0, new TestEventListener("0 1", output));
+ bus.registerEventListener(1, new TestEventListener("1 2", output));
+ bus.registerEventListener(new TestEventListener("_ 3", output));
+ bus.registerEventListener(-1, new TestEventListener("-1 4", output));
+ bus.registerEventListener(1, new TestEventListener("1 5", output));
+ bus.registerEventListener(0, new TestEventListener("0 6", output));
+
+ bus.onPlayerDeath();
+
+ assertEquals(new ArrayList<>(Arrays.asList(
+ "1 2", "1 5", "0 0", "0 1", "_ 3", "0 6", "-1 4"
+ )),
+ output
+ );
+ }
+
+ private static class TestEventListener implements AbstractGameEventListener {
+ private final String id;
+ private final List output;
+
+ public TestEventListener(String id, List output) {
+ this.id = id;
+ this.output = output;
+ }
+
+ @Override
+ public void onPlayerDeath() { // the only event without an argument ☺
+ output.add(id);
+ }
+ }
+}