Description
Consider the following event code:
public sealed interface ExampleEvent extends InheritableEvent {
EventBus<ExampleEvent> BUS = EventBus.create(ExampleEvent.class);
record Pre() implements Cancellable, ExampleEvent {
public static final CancellableEventBus<Pre> BUS = CancellableEventBus.create(Pre.class);
}
record Post() implements ExampleEvent {
public static final EventBus<Post> BUS = EventBus.create(Post.class);
}
}
Crash report: https://gist.github.com/mysticdrew/170e70612dc7ddbdb33168377f209752
Relevant exception stacktrace:
java.lang.IllegalStateException: Unexpected listener type: class net.minecraftforge.eventbus.internal.EventListenerImpl$ConsumerListener
at SECURE-BOOTSTRAP/net.minecraftforge.eventbus/net.minecraftforge.eventbus.internal.InvokerFactoryUtils.unwrapPredicates(InvokerFactoryUtils.java:55) ~[eventbus-7.0-beta.8.jar!/:7.0-beta.8]
at SECURE-BOOTSTRAP/net.minecraftforge.eventbus/net.minecraftforge.eventbus.internal.InvokerFactory.createCancellableInvoker(InvokerFactory.java:205) ~[eventbus-7.0-beta.8.jar!/:7.0-beta.8]
at SECURE-BOOTSTRAP/net.minecraftforge.eventbus/net.minecraftforge.eventbus.internal.InvokerFactory.createCancellableMonitoringInvoker(InvokerFactory.java:116) ~[eventbus-7.0-beta.8.jar!/:7.0-beta.8]
at SECURE-BOOTSTRAP/net.minecraftforge.eventbus/net.minecraftforge.eventbus.internal.CancellableEventBusImpl.buildInvoker(CancellableEventBusImpl.java:142) ~[eventbus-7.0-beta.8.jar!/:7.0-beta.8]
at SECURE-BOOTSTRAP/net.minecraftforge.eventbus/net.minecraftforge.eventbus.internal.CancellableEventBusImpl.buildInvoker(CancellableEventBusImpl.java:24) ~[eventbus-7.0-beta.8.jar!/:7.0-beta.8]
at SECURE-BOOTSTRAP/net.minecraftforge.eventbus/net.minecraftforge.eventbus.internal.AbstractEventBusImpl.getInvoker(AbstractEventBusImpl.java:130) ~[eventbus-7.0-beta.8.jar!/:7.0-beta.8]
at SECURE-BOOTSTRAP/net.minecraftforge.eventbus/net.minecraftforge.eventbus.internal.CancellableEventBusImpl.post(CancellableEventBusImpl.java:104) ~[eventbus-7.0-beta.8.jar!/:7.0-beta.8]
The issue is the conversion from Consumer
to EventListener
is done inside EventBusImpl
without considering the possibility of Cancellable
children, which need a WrappedConsumerListener
instead of a ConsumerListener
. The proper fix is to figure out a good way of accounting for that. A dumb fix that’ll work but use more memory is to always use a WrappedConsumerListener
. The hotfix I’ll be doing for now is manually checking for a ConsumerListener
inside unwrapPredicates()
and do the conversion on the fly.
The issue with doing it on the fly is that it might not allow for cancellation checks to always be skipped in cases where it should, as the system doesn't yet have the knowledge that an ordinary ConsumerListener
is never cancelling.