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 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