Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@
* {@linkplain EventListener#alwaysCancelling() always cancel} the event. The specialized
* {@link #addListener(Predicate)} method, along with its sisters in this class, are designed to give event listeners
* that characteristic.</p>
* <p>When a listener is registered, it is not invoked if the event has been cancelled. The only exception to this is
* for {@linkplain Priority#MONITOR monitoring} listeners, which are always invoked at the end of the event posting even
* if the event was cancelled. Monitoring listeners can be added using either the {@link Priority#MONITOR} priority or
* by registering an {@link ObjBooleanBiConsumer} in {@link #addListener(ObjBooleanBiConsumer)}. <strong>Monitoring
* listeners are forbidden from mutating events.</strong> This contract can be strengthened by the event author using
* the {@link net.minecraftforge.eventbus.api.event.characteristic.MonitorAware} characteristic.</p>
*
* <h2>Example</h2>
* <p>Here is a small example that showcases the different listeners this type of event bus can have.</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
* Copyright (c) Forge Development LLC
* SPDX-License-Identifier: LGPL-2.1-only
*/
/**
* EventBus is built around the idea of {@linkplain net.minecraftforge.eventbus.api.bus.EventBus event buses} that are
* grouped together by {@linkplain net.minecraftforge.eventbus.api.bus.BusGroup bus groups}. This package contains this
* core part of the API.
*/
@NullMarked
package net.minecraftforge.eventbus.api.bus;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,14 @@
import net.minecraftforge.eventbus.internal.Event;

/**
* A cancellable event returns {@code true} from {@link CancellableEventBus#post(Event)} if it was cancelled.
* <p>When an event is cancelled, it will not be passed to any further non-monitor listeners.</p>
* The ability to cancel an event is one of the core functionalities of EventBus. This functionality is carried in to
* this iteration of the EventBus API with the introduction of the cancellable
* {@linkplain net.minecraftforge.eventbus.api.event.characteristic characteristic}.
* <p>A cancellable event returns {@code true} from {@link CancellableEventBus#post(Event)} if it was cancelled. When
* an event is cancelled, it will not be passed to any further
* non-{@linkplain net.minecraftforge.eventbus.api.listener.Priority#MONITOR monitor} listeners. For further details on
* a cancellable event's interactions with an event bus, see {@link CancellableEventBus}.</p>
*
* @see CancellableEventBus
*/
public non-sealed interface Cancellable extends EventCharacteristic {}
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,29 @@
import org.jetbrains.annotations.Contract;

/**
* Events that are {@link MonitorAware} can provide stronger immutability guarantees to monitor listeners by returning
* unmodifiable views or throwing exceptions on mutation attempts when monitoring.
* <p>Only supported for {@link MutableEvent} at this time.</p>
* Events that are {@linkplain net.minecraftforge.eventbus.api.listener.Priority#MONITOR monitor}-aware are able to
* provide stronger immutability guarantees to monitor listeners by returning unmodifiable views and ignoring (or
* throwing exceptions) on mutation attempts when monitoring.
*
* @implNote This characteristic is only supported for {@link MutableEvent} at this time. If used on any other type that
* does not extend it, an {@link IllegalArgumentException} will be thrown when the
* {@linkplain net.minecraftforge.eventbus.api.bus.EventBus event bus} is created for it.
* @apiNote <strong>This is an experimental feature!</strong> It may be removed, renamed or otherwise changed without
* notice.
*/
@ApiStatus.Experimental
public non-sealed interface MonitorAware extends EventCharacteristic {
/**
* Checks if this event is currently being
* {@linkplain net.minecraftforge.eventbus.api.listener.Priority#MONITOR monitored}. This can be used to provide
* stronger immutability guarantees as described by the documentation of {@link MonitorAware}.
*
* @return
* @implSpec This method
* <strong>{@linkplain org.jetbrains.annotations.ApiStatus.NonExtendable must not be overridden}!</strong> It uses
* internals of {@link MutableEvent} in order to determine the monitoring state of the event. If overridden, your
* event will be unable to determine if it is actually monitoring!
*/
@Contract(pure = true)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method isn't pure because it can return different values based on when it is executed (false when normal priority listeners are running, true when monitoring priority listeners are running). A method is only pure if it always returns the same value when given the same arguments.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noted, thanks.

@ApiStatus.NonExtendable
default boolean isMonitoring() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@
package net.minecraftforge.eventbus.api.event.characteristic;

import net.minecraftforge.eventbus.api.bus.EventBus;
import net.minecraftforge.eventbus.internal.AbstractEventBusImpl;

/**
* A self-destructing event will {@link AbstractEventBusImpl#dispose() dispose} of its associated {@link EventBus}
* after it has been posted to free up resources, after which it cannot be posted to again.
* A self-destructing event will {@linkplain net.minecraftforge.eventbus.api.bus.BusGroup#dispose() dispose} of its
* associated {@link EventBus} after it has been posted to free up resources.
* <p>This is useful for single-use lifecycle events.</p>
*
* @apiNote Similar to {@link net.minecraftforge.eventbus.api.bus.BusGroup#dispose()}, the posting of this event is a
* destructive action that will cause its resources to be freed. <strong>It must not be used after it is
* posted!</strong>
Comment on lines +14 to +16
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

iirc this is enforced at runtime to make it a no-op, so "cannot be used" is clearer to me than "must not be used", as the latter implies an exception would be thrown. It's no-op instead of exception for performance reasons.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah it is no-op? I must've misread the internals then. I was under the assumption that disposing of a bus group is equivalent to free() in C.

*/
public non-sealed interface SelfDestructing extends EventCharacteristic {}
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
import org.jetbrains.annotations.Contract;

/**
* Self-posting events are associated with a default {@link EventBus} in order to offer some convenience instance
* methods.
* Self-posting events are associated with a default {@linkplain EventBus event bus} in order to offer some convenient
* instance methods.
*
* <h2>Example</h2>
* {@snippet :
Expand Down Expand Up @@ -40,21 +40,36 @@
@ApiStatus.Experimental
public non-sealed interface SelfPosting<T extends Event> extends EventCharacteristic {
/**
* @implSpec This should directly return a {@code static final} field without additional logic or processing.
* The default event bus for this event. It will be used by the {@link #post()} and {@link #fire()} methods.
*
* @return The default event bus for this event
* @implSpec This method must directly return a {@code static final} field without additional logic or processing.
* Failure to do so may result in performance hindrances.
*/
@Contract(pure = true)
EventBus<T> getDefaultBus();

/**
* Posts this event to all listeners registered to its {@linkplain #getDefaultBus() default event bus}.
*
* @return {@code true} if the event was cancelled <strong>and</strong> this event bus is a
* {@linkplain net.minecraftforge.eventbus.api.bus.CancellableEventBus cancellable event bus}
* @see EventBus#post(Event)
*/
@ApiStatus.NonExtendable
@SuppressWarnings("unchecked")
default boolean post() {
return getDefaultBus().post((T) this);
}

/**
* Fires this event to all listeners registered to its {@linkplain #getDefaultBus() default event bus}.
* <p>After posting, this event is returned from this method. <i>It may be mutated.</i></p>
*
* @return This event after being posted
* @see EventBus#fire(Event)
*/
@ApiStatus.NonExtendable
@Contract(value = "-> this")
@SuppressWarnings("unchecked")
default T fire() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
* Copyright (c) Forge Development LLC
* SPDX-License-Identifier: LGPL-2.1-only
*/
/**
* Events can have characteristics that define how they behave. These characterists are computed when the
* {@linkplain net.minecraftforge.eventbus.api.bus.EventBus event bus} for the specific even is created, and those
* characteristics are defined as interfaces which the event type can implement.
*/
@NullMarked
package net.minecraftforge.eventbus.api.event.characteristic;

Expand Down