From bcc575b0efcf5e358c9d35a99dad6c36eb73be07 Mon Sep 17 00:00:00 2001
From: Paint_Ninja
Date: Sat, 10 May 2025 12:53:29 +0100
Subject: [PATCH 1/8] BusGroup docs
Co-Authored-By: Jonathing
---
.../eventbus/api/bus/BusGroup.java | 53 ++++++++++++++++---
1 file changed, 47 insertions(+), 6 deletions(-)
diff --git a/src/main/java/net/minecraftforge/eventbus/api/bus/BusGroup.java b/src/main/java/net/minecraftforge/eventbus/api/bus/BusGroup.java
index 3bb95598..f2548bc2 100644
--- a/src/main/java/net/minecraftforge/eventbus/api/bus/BusGroup.java
+++ b/src/main/java/net/minecraftforge/eventbus/api/bus/BusGroup.java
@@ -9,25 +9,47 @@
import net.minecraftforge.eventbus.api.listener.SubscribeEvent;
import net.minecraftforge.eventbus.internal.BusGroupImpl;
+import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandles;
import java.util.Collection;
/**
- * A collection of {@link EventBus} instances that are grouped together for easier management.
+ * A collection of {@link EventBus} instances that are grouped together for easier management, allowing for bulk
+ * operations.
*/
public sealed interface BusGroup permits BusGroupImpl {
+ /**
+ * The default BusGroup, which is used when an {@link EventBus} is created without specifying a BusGroup.
+ */
BusGroup DEFAULT = create("default");
+ /**
+ * Creates a new BusGroup with the given name.
+ *
+ * @param name The unique name of the BusGroup
+ * @return A new BusGroup with the given name
+ * @throws IllegalArgumentException if the name is already in use by another BusGroup
+ * @apiNote To enforce a base type for all events in this BusGroup, use {@link #create(String, Class)}.
+ */
static BusGroup create(String name) {
return new BusGroupImpl(name, Event.class);
}
+ /**
+ * Creates a new BusGroup with the given name and base type.
+ *
+ * @param name The unique name of the BusGroup
+ * @param baseType The base type that all events in this BusGroup must extend or implement
+ * @return A new BusGroup with the given name and base type
+ * @throws IllegalArgumentException if the name is already in use by another BusGroup
+ */
static BusGroup create(String name, Class> baseType) {
return new BusGroupImpl(name, baseType);
}
/**
* The unique name of this BusGroup.
+ * The uniqueness of this name is enforced when the bus group is {@linkplain #create(String) created}.
*/
String name();
@@ -40,21 +62,30 @@ static BusGroup create(String name, Class> baseType) {
/**
* Shuts down all EventBus instances associated with this BusGroup, preventing any further events from being posted
* until {@link #startup()} is called.
+ *
+ * @apiNote If you don't intend on using this BusGroup again, prefer {@link #dispose()} instead as that will also
+ * free up resources.
*/
void shutdown();
/**
- * Shuts down all EventBus instances associated with this BusGroup, unregisters all listeners and frees resources
- * no longer needed.
- * Warning: This is a destructive operation - this BusGroup should not be used again after calling this method.
+ * {@linkplain #shutdown() Shuts down} all EventBus instances associated with this BusGroup,
+ * {@linkplain #unregister(Collection) unregisters} all listeners and frees no longer needed resources.
+ *
+ * Warning: This is a destructive operation - this BusGroup should not be used again after calling this method -
+ * attempting to do so may throw exceptions or act as a no-op.
+ *
+ * @apiNote If you plan on using this BusGroup again, prefer {@link #shutdown()} instead.
*/
void dispose();
/**
- * Experimental feature - may be removed, renamed or otherwise changed without notice.
- * Trims the backing lists of all EventBus instances associated with this BusGroup to free up resources.
+ * Trims the backing lists of all EventBus instances associated with this BusGroup to free up resources.
+ *
* Warning: This is only intended to be called once after all listeners are registered - calling this
* repeatedly may hurt performance.
+ *
+ * @apiNote This is an experimental feature that may be removed, renamed or otherwise changed without notice.
*/
void trim();
@@ -68,6 +99,11 @@ static BusGroup create(String name, Class> baseType) {
* @apiNote This method only registers static listeners.
* If you want to register both instance and static methods, use
* {@link BusGroup#register(MethodHandles.Lookup, Object)} instead.
+ * @implNote Internally, bulk registration uses {@link LambdaMetafactory} to create method references to the
+ * annotated methods using the provided {@code callerLookup} - said lookup must have
+ * {@linkplain MethodHandles.Lookup#hasFullPrivilegeAccess() full privilege access} as
+ * {@linkplain LambdaMetafactory LMF} may need to spin an inner class for implementing the lambda, which
+ * inherently allows access to private fields and methods.
*/
Collection register(MethodHandles.Lookup callerLookup, Class> utilityClassWithStaticListeners);
@@ -80,6 +116,11 @@ static BusGroup create(String name, Class> baseType) {
*
* @apiNote If you know all the listeners are static methods, use
* {@link BusGroup#register(MethodHandles.Lookup, Class)} instead for better registration performance.
+ * @implNote Internally, bulk registration uses {@link LambdaMetafactory} to create method references to the
+ * annotated methods using the provided {@code callerLookup} - said lookup must have
+ * {@linkplain MethodHandles.Lookup#hasFullPrivilegeAccess() full privilege access} as
+ * {@linkplain LambdaMetafactory LMF} may need to spin an inner class for implementing the lambda, which
+ * inherently allows access to private fields and methods.
*/
Collection register(MethodHandles.Lookup callerLookup, Object listener);
From 9e8ab80811f0f07303f5ac7d7d3d4c07b5a8f784 Mon Sep 17 00:00:00 2001
From: Paint_Ninja
Date: Sat, 10 May 2025 13:23:19 +0100
Subject: [PATCH 2/8] EventCharacteristic docs
Co-Authored-By: Jonathing
---
.../api/event/characteristic/Cancellable.java | 7 ++++++-
.../api/event/characteristic/MonitorAware.java | 12 +++++++++++-
.../api/event/characteristic/SelfDestructing.java | 9 ++++++---
.../api/event/characteristic/SelfPosting.java | 15 +++++++++------
.../api/event/characteristic/package-info.java | 3 +++
5 files changed, 35 insertions(+), 11 deletions(-)
diff --git a/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/Cancellable.java b/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/Cancellable.java
index a01cebd2..37dd61cd 100644
--- a/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/Cancellable.java
+++ b/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/Cancellable.java
@@ -5,11 +5,16 @@
package net.minecraftforge.eventbus.api.event.characteristic;
import net.minecraftforge.eventbus.api.bus.CancellableEventBus;
+import net.minecraftforge.eventbus.api.listener.Priority;
import net.minecraftforge.eventbus.internal.Event;
import net.minecraftforge.eventbus.internal.EventCharacteristic;
/**
* 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-monitor listeners.
+ * When an event is cancelled, it will not be passed to any further non-{@linkplain Priority#MONITOR monitor}
+ * listeners.
+ * For further details on a cancellable event's interactions with an EventBus, see {@link CancellableEventBus}.
+ *
+ * @see CancellableEventBus
*/
public non-sealed interface Cancellable extends EventCharacteristic {}
diff --git a/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/MonitorAware.java b/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/MonitorAware.java
index 266d5059..6da21d03 100644
--- a/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/MonitorAware.java
+++ b/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/MonitorAware.java
@@ -4,15 +4,25 @@
*/
package net.minecraftforge.eventbus.api.event.characteristic;
+import net.minecraftforge.eventbus.api.bus.EventBus;
import net.minecraftforge.eventbus.api.event.MutableEvent;
+import net.minecraftforge.eventbus.api.event.RecordEvent;
+import net.minecraftforge.eventbus.api.listener.Priority;
import net.minecraftforge.eventbus.internal.EventCharacteristic;
import net.minecraftforge.eventbus.internal.MutableEventInternals;
/**
- * Experimental feature - may be removed, renamed or otherwise changed without notice.
+ * Events that are {@linkplain Priority#MONITOR monitor}-aware are able to provide stronger immutability guarantees to
+ * monitoring listeners by returning unmodifiable views or throwing exceptions on mutation attempts when monitoring.
+ *
* 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.
* Only supported for {@link MutableEvent} at this time.
+ *
+ * @apiNote This is an experimental feature that may be removed, renamed or otherwise changed without notice.
+ * @implNote This characteristic is only supported for the {@link MutableEvent} base type at this time.
+ * If combined with a different base type (such as {@link RecordEvent}), an exception will be thrown when
+ * attempting to create an associated {@link EventBus}.
*/
public non-sealed interface MonitorAware extends EventCharacteristic {
default boolean isMonitoring() {
diff --git a/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/SelfDestructing.java b/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/SelfDestructing.java
index 04fc80d5..c70856ee 100644
--- a/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/SelfDestructing.java
+++ b/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/SelfDestructing.java
@@ -4,13 +4,16 @@
*/
package net.minecraftforge.eventbus.api.event.characteristic;
+import net.minecraftforge.eventbus.api.bus.BusGroup;
import net.minecraftforge.eventbus.api.bus.EventBus;
-import net.minecraftforge.eventbus.internal.AbstractEventBusImpl;
import net.minecraftforge.eventbus.internal.EventCharacteristic;
/**
- * 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 {@link BusGroup#dispose() dispose} of its associated {@link EventBus} after it has
+ * been posted to free up resources, after which it cannot be posted to again.
* This is useful for single-use lifecycle events.
+ *
+ * @apiNote The dispose action is similar to {@link BusGroup#dispose()}, but applies to only this event rather than to
+ * all events in the group.
*/
public non-sealed interface SelfDestructing extends EventCharacteristic {}
diff --git a/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/SelfPosting.java b/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/SelfPosting.java
index fdf21f1d..4e028e47 100644
--- a/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/SelfPosting.java
+++ b/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/SelfPosting.java
@@ -9,12 +9,12 @@
import net.minecraftforge.eventbus.internal.EventCharacteristic;
/**
- * Experimental feature - may be removed, renamed or otherwise changed without notice.
- * {@link SelfPosting} events are associated with a default {@link EventBus} in order to offer some convenience
- * instance methods.
- * Example
+ * Self-posting events are associated with a default {@link EventBus}, allowing for some convenience methods on the
+ * instance.
+ *
+ * Example
* {@snippet :
- * import net.minecraftforge.eventbus.api.event.RecordEvent;
+ * import module net.minecraftforge.eventbus;
*
* // Event declaration
* public record ExampleEvent() implements SelfPosting, RecordEvent {
@@ -32,10 +32,13 @@
* // instead of this
* ExampleEvent.BUS.post(new ExampleEvent());
*}
+ *
+ * @apiNote This is an experimental feature that may be removed, renamed or otherwise changed without notice.
*/
public non-sealed interface SelfPosting extends EventCharacteristic {
/**
- * @implSpec This should directly return a {@code static final} field without additional logic or processing.
+ * @implSpec This should directly return a {@code static final} field without additional logic or processing -
+ * failure to do so may hurt performance.
*/
EventBus getDefaultBus();
diff --git a/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/package-info.java b/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/package-info.java
index 37c81f0c..ef542dbc 100644
--- a/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/package-info.java
+++ b/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/package-info.java
@@ -2,6 +2,9 @@
* Copyright (c) Forge Development LLC
* SPDX-License-Identifier: LGPL-2.1-only
*/
+/**
+ * Events can have characteristics that define how they behave, composed by implementing interfaces.
+ */
@NullMarked
package net.minecraftforge.eventbus.api.event.characteristic;
From 6858e2bcef2716adbc0bc2fe749d2c742bfa4c8e Mon Sep 17 00:00:00 2001
From: Paint_Ninja
Date: Sat, 10 May 2025 14:55:08 +0100
Subject: [PATCH 3/8] EventListener partial docs
Co-Authored-By: Jonathing
---
.../eventbus/api/listener/EventListener.java | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/main/java/net/minecraftforge/eventbus/api/listener/EventListener.java b/src/main/java/net/minecraftforge/eventbus/api/listener/EventListener.java
index 018f47cc..523a98ff 100644
--- a/src/main/java/net/minecraftforge/eventbus/api/listener/EventListener.java
+++ b/src/main/java/net/minecraftforge/eventbus/api/listener/EventListener.java
@@ -6,6 +6,7 @@
import net.minecraftforge.eventbus.api.bus.CancellableEventBus;
import net.minecraftforge.eventbus.api.bus.EventBus;
+import net.minecraftforge.eventbus.api.event.characteristic.Cancellable;
import net.minecraftforge.eventbus.internal.Event;
import net.minecraftforge.eventbus.internal.EventListenerImpl;
@@ -15,19 +16,22 @@
* Users can retain instances of this interface to remove listeners that were previously added to the same
* {@link EventBus}.You can obtain instances of this interface by calling any of the {@code addListener} methods
* on an EventBus, such as {@link EventBus#addListener(Consumer)}.
- * Internally, this acts as a wrapper over lambdas to give them identity, enrich debug info and to allow
- * various conversion operations to different lambda types.
+ *
+ * @implNote Internally, this acts as a wrapper over lambdas to give them identity, enrich debug info and to allow
+ * various conversion operations to different lambda types.
*/
public sealed interface EventListener permits EventListenerImpl {
@SuppressWarnings("ClassEscapesDefinedScope") // ? can be a subtype of Event which is publicly accessible
Class extends Event> eventType();
/**
+ * The priority of this listener. Higher numbers are called first.
* @see Priority
*/
byte priority();
/**
+ * Whether this listener is known to always cancel the {@link Cancellable} event when called.
* @see CancellableEventBus#addListener(boolean, Consumer)
*/
default boolean alwaysCancelling() {
From 07f5858ab9008466fd8c5b50ddb7d85ee61ec4d6 Mon Sep 17 00:00:00 2001
From: Paint_Ninja
Date: Sat, 10 May 2025 14:56:41 +0100
Subject: [PATCH 4/8] Event docs
---
.../eventbus/api/event/InheritableEvent.java | 58 +++++++++++++++++++
.../eventbus/api/event/MutableEvent.java | 10 ++++
.../eventbus/api/event/RecordEvent.java | 25 ++++++++
.../eventbus/internal/Event.java | 19 ++++++
4 files changed, 112 insertions(+)
diff --git a/src/main/java/net/minecraftforge/eventbus/api/event/InheritableEvent.java b/src/main/java/net/minecraftforge/eventbus/api/event/InheritableEvent.java
index f3e72517..3c139d4f 100644
--- a/src/main/java/net/minecraftforge/eventbus/api/event/InheritableEvent.java
+++ b/src/main/java/net/minecraftforge/eventbus/api/event/InheritableEvent.java
@@ -6,4 +6,62 @@
import net.minecraftforge.eventbus.internal.Event;
+/**
+ * A hybrid of an event base type and characteristic - implementing this interface on your event type allows for event
+ * posting on subclasses to propagate to your event type, essentially opting into event inheritance. This allows for
+ * flexible event hierarchies with mixed levels of encapsulation and mutability.
+ *
+ * Example
+ * In this example, we are combining InheritableEvent with {@link RecordEvent} and using the Java module system to
+ * make the record's constructor effectively internal. This allows for a stronger guarantee of correctness for listeners
+ * as it's not possible for someone else to create and post an event of this type at the wrong time or with invalid
+ * data.
+ * {@snippet :
+ * import module net.minecraftforge.eventbus;
+ *
+ * // in a publicly exported package (e.g. com.example.events.api)
+ * public sealed interface PlayerJumpEvent extends InheritableEvent permits PlayerJumpEventImpl {
+ * EventBus BUS = EventBus.create(PlayerJumpEvent.class);
+ *
+ * Player player();
+ * int jumpHeight();
+ * }
+ *
+ * // in an internal package (e.g. com.example.events.internal)
+ * public record PlayerJumpEventImpl(Player player, int jumpHeight) implements PlayerJumpEvent {
+ * public static final EventBus BUS = EventBus.create(PlayerJumpEvent.class);
+ * }
+ *
+ * // snippet of the module-info.java
+ * module com.example.events {
+ * exports com.example.events.api;
+ * // (note that the internal package is not exported)
+ * }
+ * }
+ * Consumers can add listeners to {@code PlayerJumpEvent.BUS} and would receive events posted to
+ * {@code PlayerJumpEventImpl.BUS}.
+ *
+ * Another example would be replacing an abstract class hierarchy with a sealed interface and records implementing
+ * them, like so:
+ * {@snippet :
+ * import module net.minecraftforge.eventbus;
+ *
+ * public sealed interface JumpEvent extends InheritableEvent {
+ * EventBus BUS = EventBus.create(JumpEvent.class);
+ *
+ * int jumpHeight();
+ *
+ * record PlayerJumpEvent(Player player, int jumpHeight) implements JumpEvent {
+ * public static final EventBus BUS = EventBus.create(PlayerJumpEvent.class);
+ * }
+ *
+ * record AnimalJumpEvent(Animal animal, int jumpHeight) implements JumpEvent {
+ * public static final EventBus BUS = EventBus.create(AnimalJumpEvent.class);
+ * }
+ * }
+ * }
+ * This allows consumers to add listeners to {@code JumpEvent} if they only care about the jump height, which is
+ * functionally equivalent to adding a distinct listener to all children, but more performant and less error-prone
+ * (if a new subclass is added later, it would be accounted for at runtime).
+ */
public non-sealed interface InheritableEvent extends Event {}
diff --git a/src/main/java/net/minecraftforge/eventbus/api/event/MutableEvent.java b/src/main/java/net/minecraftforge/eventbus/api/event/MutableEvent.java
index bf6f9152..53dbf0bd 100644
--- a/src/main/java/net/minecraftforge/eventbus/api/event/MutableEvent.java
+++ b/src/main/java/net/minecraftforge/eventbus/api/event/MutableEvent.java
@@ -7,4 +7,14 @@
import net.minecraftforge.eventbus.internal.Event;
import net.minecraftforge.eventbus.internal.MutableEventInternals;
+/**
+ * For mutable event classes that may also extend other classes and/or support being extended.
+ * More advanced techniques like protected fields and methods are also possible, where the supertype may be a
+ * protected abstract class with some internals handled for you, but only the concrete types are actual events.
+ *
+ * Consider {@link RecordEvent} for better performance and conciseness if field mutability and direct extendability
+ * aren't needed.
+ *
+ * @see RecordEvent
+ */
public non-sealed abstract class MutableEvent extends MutableEventInternals implements Event {}
diff --git a/src/main/java/net/minecraftforge/eventbus/api/event/RecordEvent.java b/src/main/java/net/minecraftforge/eventbus/api/event/RecordEvent.java
index 7ed4ecda..5dc16537 100644
--- a/src/main/java/net/minecraftforge/eventbus/api/event/RecordEvent.java
+++ b/src/main/java/net/minecraftforge/eventbus/api/event/RecordEvent.java
@@ -4,9 +4,34 @@
*/
package net.minecraftforge.eventbus.api.event;
+import net.minecraftforge.eventbus.api.bus.EventBus;
+import net.minecraftforge.eventbus.api.event.characteristic.Cancellable;
import net.minecraftforge.eventbus.internal.Event;
/**
* For read-only or shallowly-immutable records.
+ * Provides a means for declaring events in a concise and performant manner.
+ *
+ * Examples
+ * Here are some conceptual examples of record events:
+ *
+ * - Consider a leaderboard event that provides a list of players that listeners can mutate but doesn't allow
+ * the list to be set to null or an immutable list that would result in unexpected behaviour for the other
+ * listeners.
+ * - An event where listeners are notified of a player joining the server and can optionally cancel it to kick them
+ * (when combined with the {@link Cancellable} characteristic), but can't set the player to someone else.
+ * - Stateless events which do not carry any data inside but are still useful for notifying listeners when a
+ * specific action occurs, such as some types of lifecycle events.
+ *
+ *
+ * Note that while records are final and cannot extend other classes, inheritance is still possible through other
+ * means, such as by implementing a sealed interface and using the Java module system.
+ *
+ * @apiNote Cancellation is supported for record events as long as they also implement the {@link Cancellable}
+ * characteristic - this is possible thanks to the cancellation state being kept on the stack separately from
+ * the record instance itself.
+ * @implSpec This event base type can only be applied to {@linkplain Record Java record classes}.
+ * If you implement this interface on an ordinary class, an exception will be thrown when attempting to
+ * create an associated {@link EventBus}.
*/
public non-sealed interface RecordEvent extends Event {}
diff --git a/src/main/java/net/minecraftforge/eventbus/internal/Event.java b/src/main/java/net/minecraftforge/eventbus/internal/Event.java
index b76cc273..0e79d5ad 100644
--- a/src/main/java/net/minecraftforge/eventbus/internal/Event.java
+++ b/src/main/java/net/minecraftforge/eventbus/internal/Event.java
@@ -8,4 +8,23 @@
import net.minecraftforge.eventbus.api.event.MutableEvent;
import net.minecraftforge.eventbus.api.event.RecordEvent;
+/**
+ * The internal marker interface for all event base types. This is internal and sealed for many reasons:
+ *
+ * - To avoid ambiguity in the system where different events in the inheritance chain may technically be events
+ * but not declare their type
+ * - To discourage bad usages by library users that could hurt performance. For example, having all listeners
+ * bounce to a generic void handleEvent(Event e) method and doing chains of instanceof checks would be very
+ * slow.
+ * - To minimise the public API surface - the more we have to support, the more restricted and complicated
+ * internals become
+ *
+ *
+ * Library users should use one of the three base types instead:
+ *
+ * - {@link MutableEvent} for classes
+ * - {@link RecordEvent} for records
+ * - {@link InheritableEvent} for interfaces
+ *
+ */
public sealed interface Event permits InheritableEvent, MutableEvent, RecordEvent {}
From 6171ea8da65d66a4be093a669a3f535ff8c293f9 Mon Sep 17 00:00:00 2001
From: Paint_Ninja
Date: Sat, 31 May 2025 15:27:22 +0100
Subject: [PATCH 5/8] Minimal additional javadocs for buses
---
.../java/net/minecraftforge/eventbus/api/bus/EventBus.java | 4 ++++
.../net/minecraftforge/eventbus/api/bus/package-info.java | 5 +++++
2 files changed, 9 insertions(+)
diff --git a/src/main/java/net/minecraftforge/eventbus/api/bus/EventBus.java b/src/main/java/net/minecraftforge/eventbus/api/bus/EventBus.java
index 8daaf0b3..bb0f703a 100644
--- a/src/main/java/net/minecraftforge/eventbus/api/bus/EventBus.java
+++ b/src/main/java/net/minecraftforge/eventbus/api/bus/EventBus.java
@@ -14,6 +14,10 @@
import java.util.function.Consumer;
+/**
+ * @see CancellableEventBus if your event type implements {@link Cancellable}
+ * @param The type of event this EventBus handles
+ */
public sealed interface EventBus permits CancellableEventBus, AbstractEventBusImpl, EventBusImpl {
/**
* Adds a listener to this EventBus with the default priority of {@link Priority#NORMAL}.
diff --git a/src/main/java/net/minecraftforge/eventbus/api/bus/package-info.java b/src/main/java/net/minecraftforge/eventbus/api/bus/package-info.java
index 1eb81840..ad6166b5 100644
--- a/src/main/java/net/minecraftforge/eventbus/api/bus/package-info.java
+++ b/src/main/java/net/minecraftforge/eventbus/api/bus/package-info.java
@@ -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;
From 9c5114f7347ad4019755603dcbc866c9a81b1f14 Mon Sep 17 00:00:00 2001
From: Paint_Ninja
Date: Sat, 31 May 2025 15:30:25 +0100
Subject: [PATCH 6/8] Fix minor mistake in readme example
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 1ef76780..cc4eae54 100644
--- a/README.md
+++ b/README.md
@@ -32,7 +32,7 @@ import net.minecraftforge.eventbus.api.event.RecordEvent;
import net.minecraftforge.eventbus.api.bus.EventBus;
// Define an event and a bus for it
-record PlayerLoggedInEvent(String username) implements RecordEvent {
+public record PlayerLoggedInEvent(String username) implements RecordEvent {
public static final EventBus BUS = EventBus.create(PlayerLoggedInEvent.class);
}
From f1a0b164894a7a843a9d80f79982a898c9736967 Mon Sep 17 00:00:00 2001
From: Paint_Ninja
Date: Sat, 31 May 2025 15:34:48 +0100
Subject: [PATCH 7/8] Avoid module imports
As EB7 targets Java 21, we can't use module import statements from Java 25
---
.../minecraftforge/eventbus/api/event/InheritableEvent.java | 6 ++++--
.../eventbus/api/event/characteristic/SelfPosting.java | 4 +++-
2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/src/main/java/net/minecraftforge/eventbus/api/event/InheritableEvent.java b/src/main/java/net/minecraftforge/eventbus/api/event/InheritableEvent.java
index 3c139d4f..cee725b0 100644
--- a/src/main/java/net/minecraftforge/eventbus/api/event/InheritableEvent.java
+++ b/src/main/java/net/minecraftforge/eventbus/api/event/InheritableEvent.java
@@ -17,7 +17,8 @@
* as it's not possible for someone else to create and post an event of this type at the wrong time or with invalid
* data.
* {@snippet :
- * import module net.minecraftforge.eventbus;
+ * import net.minecraftforge.eventbus.api.bus.EventBus;
+ * import net.minecraftforge.eventbus.api.event.InheritableEvent;
*
* // in a publicly exported package (e.g. com.example.events.api)
* public sealed interface PlayerJumpEvent extends InheritableEvent permits PlayerJumpEventImpl {
@@ -44,7 +45,8 @@
* Another example would be replacing an abstract class hierarchy with a sealed interface and records implementing
* them, like so:
* {@snippet :
- * import module net.minecraftforge.eventbus;
+ * import net.minecraftforge.eventbus.api.bus.EventBus;
+ * import net.minecraftforge.eventbus.api.event.InheritableEvent;
*
* public sealed interface JumpEvent extends InheritableEvent {
* EventBus BUS = EventBus.create(JumpEvent.class);
diff --git a/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/SelfPosting.java b/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/SelfPosting.java
index 4e028e47..d3fefea7 100644
--- a/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/SelfPosting.java
+++ b/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/SelfPosting.java
@@ -14,7 +14,9 @@
*
* Example
* {@snippet :
- * import module net.minecraftforge.eventbus;
+ * import net.minecraftforge.eventbus.api.bus.EventBus;
+ * import net.minecraftforge.eventbus.api.event.RecordEvent;
+ * import net.minecraftforge.eventbus.api.event.characteristic.SelfPosting;
*
* // Event declaration
* public record ExampleEvent() implements SelfPosting, RecordEvent {
From 18327e58dde01ff8c8644c1d137a9f1ce9b2051f Mon Sep 17 00:00:00 2001
From: Paint_Ninja
Date: Wed, 27 Aug 2025 18:38:44 +0100
Subject: [PATCH 8/8] Misc changes to javadocs
---
.../eventbus/api/event/InheritableEvent.java | 55 -------------------
.../eventbus/api/event/RecordEvent.java | 4 +-
.../api/event/characteristic/Cancellable.java | 11 +++-
.../event/characteristic/MonitorAware.java | 4 --
.../eventbus/api/listener/EventListener.java | 2 +-
5 files changed, 13 insertions(+), 63 deletions(-)
diff --git a/src/main/java/net/minecraftforge/eventbus/api/event/InheritableEvent.java b/src/main/java/net/minecraftforge/eventbus/api/event/InheritableEvent.java
index cee725b0..ec2b755f 100644
--- a/src/main/java/net/minecraftforge/eventbus/api/event/InheritableEvent.java
+++ b/src/main/java/net/minecraftforge/eventbus/api/event/InheritableEvent.java
@@ -10,60 +10,5 @@
* A hybrid of an event base type and characteristic - implementing this interface on your event type allows for event
* posting on subclasses to propagate to your event type, essentially opting into event inheritance. This allows for
* flexible event hierarchies with mixed levels of encapsulation and mutability.
- *
- * Example
- * In this example, we are combining InheritableEvent with {@link RecordEvent} and using the Java module system to
- * make the record's constructor effectively internal. This allows for a stronger guarantee of correctness for listeners
- * as it's not possible for someone else to create and post an event of this type at the wrong time or with invalid
- * data.
- * {@snippet :
- * import net.minecraftforge.eventbus.api.bus.EventBus;
- * import net.minecraftforge.eventbus.api.event.InheritableEvent;
- *
- * // in a publicly exported package (e.g. com.example.events.api)
- * public sealed interface PlayerJumpEvent extends InheritableEvent permits PlayerJumpEventImpl {
- * EventBus BUS = EventBus.create(PlayerJumpEvent.class);
- *
- * Player player();
- * int jumpHeight();
- * }
- *
- * // in an internal package (e.g. com.example.events.internal)
- * public record PlayerJumpEventImpl(Player player, int jumpHeight) implements PlayerJumpEvent {
- * public static final EventBus BUS = EventBus.create(PlayerJumpEvent.class);
- * }
- *
- * // snippet of the module-info.java
- * module com.example.events {
- * exports com.example.events.api;
- * // (note that the internal package is not exported)
- * }
- * }
- * Consumers can add listeners to {@code PlayerJumpEvent.BUS} and would receive events posted to
- * {@code PlayerJumpEventImpl.BUS}.
- *
- * Another example would be replacing an abstract class hierarchy with a sealed interface and records implementing
- * them, like so:
- * {@snippet :
- * import net.minecraftforge.eventbus.api.bus.EventBus;
- * import net.minecraftforge.eventbus.api.event.InheritableEvent;
- *
- * public sealed interface JumpEvent extends InheritableEvent {
- * EventBus BUS = EventBus.create(JumpEvent.class);
- *
- * int jumpHeight();
- *
- * record PlayerJumpEvent(Player player, int jumpHeight) implements JumpEvent {
- * public static final EventBus BUS = EventBus.create(PlayerJumpEvent.class);
- * }
- *
- * record AnimalJumpEvent(Animal animal, int jumpHeight) implements JumpEvent {
- * public static final EventBus BUS = EventBus.create(AnimalJumpEvent.class);
- * }
- * }
- * }
- * This allows consumers to add listeners to {@code JumpEvent} if they only care about the jump height, which is
- * functionally equivalent to adding a distinct listener to all children, but more performant and less error-prone
- * (if a new subclass is added later, it would be accounted for at runtime).
*/
public non-sealed interface InheritableEvent extends Event {}
diff --git a/src/main/java/net/minecraftforge/eventbus/api/event/RecordEvent.java b/src/main/java/net/minecraftforge/eventbus/api/event/RecordEvent.java
index 5dc16537..5cdfe349 100644
--- a/src/main/java/net/minecraftforge/eventbus/api/event/RecordEvent.java
+++ b/src/main/java/net/minecraftforge/eventbus/api/event/RecordEvent.java
@@ -20,8 +20,8 @@
* listeners.
* An event where listeners are notified of a player joining the server and can optionally cancel it to kick them
* (when combined with the {@link Cancellable} characteristic), but can't set the player to someone else.
- * Stateless events which do not carry any data inside but are still useful for notifying listeners when a
- * specific action occurs, such as some types of lifecycle events.
+ * Stateless events which do not carry any data inside but are still useful for notifying listeners when
+ * a specific action occurs, such as some types of lifecycle events.
*
*
* Note that while records are final and cannot extend other classes, inheritance is still possible through other
diff --git a/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/Cancellable.java b/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/Cancellable.java
index 37dd61cd..1d126c95 100644
--- a/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/Cancellable.java
+++ b/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/Cancellable.java
@@ -5,16 +5,25 @@
package net.minecraftforge.eventbus.api.event.characteristic;
import net.minecraftforge.eventbus.api.bus.CancellableEventBus;
+import net.minecraftforge.eventbus.api.event.RecordEvent;
import net.minecraftforge.eventbus.api.listener.Priority;
import net.minecraftforge.eventbus.internal.Event;
import net.minecraftforge.eventbus.internal.EventCharacteristic;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+
/**
- * A cancellable event returns {@code true} from {@link CancellableEventBus#post(Event)} if it was cancelled.
+ * A cancellable event returns {@code true} from {@link CancellableEventBus#post(Event)} if it was cancelled by a
+ * {@linkplain CancellableEventBus#addListener(Predicate) 'maybe cancelling'} or
+ * {@linkplain CancellableEventBus#addListener(boolean, Consumer) 'always cancelling'} listener.
+ *
*
When an event is cancelled, it will not be passed to any further non-{@linkplain Priority#MONITOR monitor}
* listeners.
* For further details on a cancellable event's interactions with an EventBus, see {@link CancellableEventBus}.
*
+ * @implNote Internally, the cancellation state is kept on the stack separately from the event instance itself, allowing
+ * for this characteristic to be applied to any event type - even {@link RecordEvent}s.
* @see CancellableEventBus
*/
public non-sealed interface Cancellable extends EventCharacteristic {}
diff --git a/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/MonitorAware.java b/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/MonitorAware.java
index 6da21d03..815d6d47 100644
--- a/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/MonitorAware.java
+++ b/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/MonitorAware.java
@@ -15,10 +15,6 @@
* Events that are {@linkplain Priority#MONITOR monitor}-aware are able to provide stronger immutability guarantees to
* monitoring listeners by returning unmodifiable views or throwing exceptions on mutation attempts when monitoring.
*
- * 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.
- * Only supported for {@link MutableEvent} at this time.
- *
* @apiNote This is an experimental feature that may be removed, renamed or otherwise changed without notice.
* @implNote This characteristic is only supported for the {@link MutableEvent} base type at this time.
* If combined with a different base type (such as {@link RecordEvent}), an exception will be thrown when
diff --git a/src/main/java/net/minecraftforge/eventbus/api/listener/EventListener.java b/src/main/java/net/minecraftforge/eventbus/api/listener/EventListener.java
index 523a98ff..5db6e589 100644
--- a/src/main/java/net/minecraftforge/eventbus/api/listener/EventListener.java
+++ b/src/main/java/net/minecraftforge/eventbus/api/listener/EventListener.java
@@ -14,7 +14,7 @@
/**
* Users can retain instances of this interface to remove listeners that were previously added to the same
- * {@link EventBus}.You can obtain instances of this interface by calling any of the {@code addListener} methods
+ * {@link EventBus}. You can obtain instances of this interface by calling any of the {@code addListener} methods
* on an EventBus, such as {@link EventBus#addListener(Consumer)}.
*
* @implNote Internally, this acts as a wrapper over lambdas to give them identity, enrich debug info and to allow