Skip to content

Commit 71546dc

Browse files
authored
Fix posting cancellable children with non-cancellable inheritable parents (#91)
1 parent 0949732 commit 71546dc

File tree

3 files changed

+31
-1
lines changed

3 files changed

+31
-1
lines changed

eventbus-test/src/test/java/net/minecraftforge/eventbus/test/InheritanceTests.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import net.minecraftforge.eventbus.api.bus.EventBus;
88
import net.minecraftforge.eventbus.api.event.InheritableEvent;
99
import net.minecraftforge.eventbus.api.event.MutableEvent;
10+
import net.minecraftforge.eventbus.api.event.characteristic.Cancellable;
1011
import net.minecraftforge.eventbus.internal.EventBusImpl;
1112
import org.junit.jupiter.api.Assertions;
1213
import org.junit.jupiter.api.Test;
@@ -206,4 +207,28 @@ final class SubEvent extends SuperEvent {
206207
SuperEvent.BUS.removeListener(listener);
207208
}
208209

210+
/**
211+
* Tests that listener inheritance works when a non-{@link Cancellable} parent event implements {@link InheritableEvent}
212+
* and a {@link Cancellable} child event inherits from the parent.
213+
*/
214+
@Test
215+
public void testListenerCallInheritanceWithCancellable() {
216+
class SuperEvent implements InheritableEvent {
217+
static final EventBus<SuperEvent> BUS = EventBus.create(SuperEvent.class);
218+
}
219+
final class SubEvent extends SuperEvent implements Cancellable {
220+
static final EventBus<SubEvent> BUS = EventBus.create(SubEvent.class);
221+
}
222+
223+
var handled = new AtomicBoolean();
224+
var listener = SuperEvent.BUS.addListener(event -> handled.set(true));
225+
226+
Assertions.assertFalse(handled.get(), "SuperEvent should not be handled yet");
227+
228+
Assertions.assertDoesNotThrow(() -> SubEvent.BUS.post(new SubEvent()));
229+
230+
Assertions.assertTrue(handled.get(), "SuperEvent should be handled, even though SubEvent is cancellable");
231+
232+
SuperEvent.BUS.removeListener(listener);
233+
}
209234
}

src/main/java/net/minecraftforge/eventbus/internal/EventListenerImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public WrappedConsumerListener(Class<? extends Event> eventType, byte priority,
7373
* @implNote We avoid capturing the alwaysCancelling field in the lambda so that the bytecode is generated as a
7474
* {@code ICONST_1} or {@code ICONST_0} instruction, rather than a field load.
7575
*/
76-
private static Predicate<Event> wrap(boolean alwaysCancelling, Consumer<Event> consumer) {
76+
public static Predicate<Event> wrap(boolean alwaysCancelling, Consumer<Event> consumer) {
7777
if (alwaysCancelling) {
7878
return event -> {
7979
consumer.accept(event);

src/main/java/net/minecraftforge/eventbus/internal/InvokerFactoryUtils.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ static <T> List<Predicate<T>> unwrapPredicates(List<EventListener> listeners) {
5151
for (var listener : listeners) {
5252
if (listener instanceof EventListenerImpl.HasPredicate<?> predicateListener) {
5353
unwrappedPredicates.add(uncheckedCast(predicateListener.predicate()));
54+
} else if (listener instanceof EventListenerImpl.ConsumerListener consumerListener) {
55+
// EventBus#90 hotfix
56+
// Todo: Figure out a smarter way to handle this, such as when the listener is added to the EventBus and converted to an EventListener.
57+
// Refer to the GitHub issue for more details.
58+
unwrappedPredicates.add(uncheckedCast(EventListenerImpl.WrappedConsumerListener.wrap(false, consumerListener.consumer())));
5459
} else {
5560
throw new IllegalStateException("Unexpected listener type: " + listener.getClass());
5661
}

0 commit comments

Comments
 (0)