### Define an Example Event Listener and Event Source: https://github.com/florianreuth/dietrichevents2/blob/main/README.md Defines an interface for event listeners and an abstract event class. The event class requires an incremented ID and a call method to invoke listener methods. ```java public interface ExampleListener { void onTest(final String example); class ExampleEvent extends AbstractEvent { /** * The ID has to be incremented for every new Event */ public static final int ID = 0; public final String example; public ExampleEvent(final String example) { this.example = example; } @Override public void call(ExampleListener listener) { listener.onTest(example); } } } ``` -------------------------------- ### DietrichEvents2 - Creating an Instance Source: https://context7.com/florianreuth/dietrichevents2/llms.txt Demonstrates how to create instances of the DietrichEvents2 event bus, including using the global singleton and creating custom instances with specific capacities and error handlers. ```APIDOC ## Creating an Instance The main class can be instantiated with a custom event capacity and a `Consumer` error handler, or accessed through a built-in global singleton. `eventCapacity` sets the initial size of the internal subscriber array; it auto-resizes when events with higher IDs are registered. ### Usage ```java import de.florianreuth.dietrichevents2.DietrichEvents2; // Use the global singleton (default capacity 32, prints stack traces on error) DietrichEvents2 bus = DietrichEvents2.global(); // Create a dedicated instance with custom capacity and error handler DietrichEvents2 bus = new DietrichEvents2(64, throwable -> { System.err.println("Event error: " + throwable.getMessage()); }); // Minimal instance (capacity only, default error handler) DietrichEvents2 bus = new DietrichEvents2(16); ``` ``` -------------------------------- ### Using Priority Constants for Listener Execution Order Source: https://context7.com/florianreuth/dietrichevents2/llms.txt Optional constants for subscriber priority values. Lower integers execute earlier. `MONITOR` runs first, `FALLBACK` runs last. Default priority is `NORMAL` (0). ```java import de.florianreuth.dietrichevents2.Priorities; // Available constants: // Priorities.MONITOR = Integer.MIN_VALUE (runs first) // Priorities.HIGHEST = -2 // Priorities.HIGH = -1 // Priorities.NORMAL = 0 (default) // Priorities.LOW = 1 // Priorities.LOWEST = 2 // Priorities.FALLBACK = Integer.MAX_VALUE (runs last) DietrichEvents2 bus = DietrichEvents2.global(); bus.subscribe(PlayerListener.PlayerJoinEvent.ID, authChecker, Priorities.HIGHEST); bus.subscribe(PlayerListener.PlayerJoinEvent.ID, mainLogic, Priorities.NORMAL); bus.subscribe(PlayerListener.PlayerJoinEvent.ID, auditTrailer, Priorities.MONITOR); // Execution order: auditTrailer → authChecker → mainLogic ``` -------------------------------- ### Subscribe with Priority Source: https://context7.com/florianreuth/dietrichevents2/llms.txt Register subscribers with different priority levels. Lower numerical values indicate higher priority. Subscribers with the same priority are ordered by insertion time. ```java import de.florianreuth.dietrichevents2.DietrichEvents2; import de.florianreuth.dietrichevents2.Priorities; DietrichEvents2 bus = DietrichEvents2.global(); // MONITOR (-MIN_VALUE) runs first, FALLBACK (MAX_VALUE) runs last bus.subscribe(PlayerListener.PlayerJoinEvent.ID, auditLogger, Priorities.MONITOR); bus.subscribe(PlayerListener.PlayerJoinEvent.ID, securityCheck, Priorities.HIGHEST); // -2 bus.subscribe(PlayerListener.PlayerJoinEvent.ID, mainHandler, Priorities.NORMAL); // 0 (default) bus.subscribe(PlayerListener.PlayerJoinEvent.ID, statsTracker, Priorities.LOW); // 1 bus.subscribe(PlayerListener.PlayerJoinEvent.ID, fallback, Priorities.FALLBACK); // Execution order: MONITOR → HIGHEST → NORMAL → LOW → FALLBACK bus.call(PlayerListener.PlayerJoinEvent.ID, new PlayerListener.PlayerJoinEvent("Alice", System.currentTimeMillis())); // Output: auditLogger → securityCheck → mainHandler → statsTracker → fallback ``` -------------------------------- ### subscribe(int id, Object object) — Registering a Listener Source: https://context7.com/florianreuth/dietrichevents2/llms.txt Details how to register listeners with the event bus using the `subscribe` method. Listeners can be class instances or lambda expressions, and they are delivered in priority order. ```APIDOC ## subscribe(int id, Object object) — Registering a Listener Subscribes any object (typically implementing the listener interface) to receive events by ID. Lambda expressions can be used directly when the listener is a functional interface. Multiple calls with the same object are allowed. Subscribers are inserted in priority order (lower integer = earlier execution). ### Usage ```java import de.florianreuth.dietrichevents2.DietrichEvents2; DietrichEvents2 bus = DietrichEvents2.global(); // Subscribe a class instance public class PlayerHandler implements PlayerListener { public PlayerHandler() { bus.subscribe(PlayerListener.PlayerJoinEvent.ID, this); } @Override public void onPlayerJoin(PlayerJoinEvent event) { System.out.println("Player joined: " + event.playerName); } } // Subscribe a lambda (PlayerListener is a functional interface with one abstract method) bus.subscribe(PlayerListener.PlayerJoinEvent.ID, (PlayerListener) event -> System.out.println("Lambda: " + event.playerName)); // Subscribe to multiple events at once bus.subscribe(handler, PlayerListener.PlayerJoinEvent.ID, PlayerListener.PlayerLeaveEvent.ID); ``` ``` -------------------------------- ### Create DietrichEvents2 Instance Source: https://context7.com/florianreuth/dietrichevents2/llms.txt Instantiate the event bus using the global singleton, or create a dedicated instance with custom capacity and an error handler. The capacity determines the initial size of the internal subscriber array. ```java import de.florianreuth.dietrichevents2.DietrichEvents2; // Use the global singleton (default capacity 32, prints stack traces on error) DietrichEvents2 bus = DietrichEvents2.global(); // Create a dedicated instance with custom capacity and error handler DietrichEvents2 bus = new DietrichEvents2(64, throwable -> { System.err.println("Event error: " + throwable.getMessage()); }); // Minimal instance (capacity only, default error handler) DietrichEvents2 bus = new DietrichEvents2(16); ``` -------------------------------- ### Register an Event Listener Source: https://github.com/florianreuth/dietrichevents2/blob/main/README.md Subscribes an instance of a listener to a specific event ID using the global event system. It also demonstrates unsubscribing after execution. ```java public class Test implements ExampleListener { public void begin() { DietrichEvents2.global().subscribe(ExampleEvent.ID, this); } @Override public void onTest(String example) { System.out.println("Executed once!"); DietrichEvents2.global().unsubscribe(ExampleEvent.ID, this); } } ``` -------------------------------- ### subscribe(int id, Object object, int priority) Source: https://context7.com/florianreuth/dietrichevents2/llms.txt Registers a subscriber with a specific event ID and priority. Lower numerical priority values are executed first. Subscribers with the same priority are ordered by insertion time. ```APIDOC ## `subscribe(int id, Object object, int priority)` — Registering with Priority Subscribers are delivered events in ascending priority order (numerically lower values run first). The `Priorities` constants provide semantic names; custom integer values are also valid. Subscribers with the same priority are ordered by insertion time. ### Method `subscribe` ### Parameters #### Path Parameters - **id** (int) - Required - The unique identifier for the event. - **object** (Object) - Required - The subscriber object that will handle the event. - **priority** (int) - Required - The priority level for the subscriber. Lower values indicate higher priority. ### Request Example ```java import de.florianreuth.dietrichevents2.DietrichEvents2; import de.florianreuth.dietrichevents2.Priorities; DietrichEvents2 bus = DietrichEvents2.global(); // MONITOR (-MIN_VALUE) runs first, FALLBACK (MAX_VALUE) runs last bus.subscribe(PlayerListener.PlayerJoinEvent.ID, auditLogger, Priorities.MONITOR); bus.subscribe(PlayerListener.PlayerJoinEvent.ID, securityCheck, Priorities.HIGHEST); // -2 bus.subscribe(PlayerListener.PlayerJoinEvent.ID, mainHandler, Priorities.NORMAL); // 0 (default) bus.subscribe(PlayerListener.PlayerJoinEvent.ID, statsTracker, Priorities.LOW); // 1 bus.subscribe(PlayerListener.PlayerJoinEvent.ID, fallback, Priorities.FALLBACK); // Execution order: MONITOR → HIGHEST → NORMAL → LOW → FALLBACK bus.call(PlayerListener.PlayerJoinEvent.ID, new PlayerListener.PlayerJoinEvent("Alice", System.currentTimeMillis())); // Output: auditLogger → securityCheck → mainHandler → statsTracker → fallback ``` ``` -------------------------------- ### hasSubscriber / isSubscriber / getSubscribers Source: https://context7.com/florianreuth/dietrichevents2/llms.txt Utility methods for inspecting the current subscriber state. `hasSubscriber(id)` checks if any listeners are registered for an event ID. `isSubscriber(id, object)` verifies if a specific listener object is subscribed to an event ID using identity comparison. `getSubscribers(id)` returns the raw array of listeners or null if none are registered. ```APIDOC ## hasSubscriber / isSubscriber / getSubscribers ### Description Utility methods for inspecting the current subscriber state. `hasSubscriber(id)` returns `true` if any listeners are registered. `isSubscriber(id, object)` checks for a specific object using identity (`==`). `getSubscribers(id)` returns the raw `Object[]` array, or `null` if empty. ### Method Signatures * `hasSubscriber(int id)` * `isSubscriber(int id, Object object)` * `getSubscribers(int id)` ### Parameters * **id** (int) - The ID of the event to query. * **object** (Object) - The listener object to check for (used with `isSubscriber`). ### Example ```java import de.florianreuth.dietrichevents2.DietrichEvents2; DietrichEvents2 bus = DietrichEvents2.global(); PlayerListener handler = event -> {}; bus.subscribe(PlayerListener.PlayerJoinEvent.ID, handler); boolean hasAny = bus.hasSubscriber(PlayerListener.PlayerJoinEvent.ID); // true boolean isRegistered = bus.isSubscriber(PlayerListener.PlayerJoinEvent.ID, handler); // true Object[] all = bus.getSubscribers(PlayerListener.PlayerJoinEvent.ID); // [handler] bus.unsubscribeAll(PlayerListener.PlayerJoinEvent.ID); Object[] none = bus.getSubscribers(PlayerListener.PlayerJoinEvent.ID); // null ``` ``` -------------------------------- ### AbstractEvent - Defining an Event Source: https://context7.com/florianreuth/dietrichevents2/llms.txt Explains how to define custom events using the `AbstractEvent` functional interface. Each event must declare a unique static `int ID` and implement the `call` method to dispatch to listeners. ```APIDOC ## AbstractEvent — Defining an Event `AbstractEvent` is the functional interface every event must implement. The type parameter `T` is the listener interface. Each event class must declare a unique static `int ID`, which is used as the event's identifier throughout the system. ### Usage ```java import de.florianreuth.dietrichevents2.AbstractEvent; // Define the listener interface and its nested event class together public interface PlayerListener { void onPlayerJoin(PlayerJoinEvent event); class PlayerJoinEvent implements AbstractEvent { // Each event type needs a unique ID, starting from 0 public static final int ID = 0; public final String playerName; public final long timestamp; public PlayerJoinEvent(String playerName, long timestamp) { this.playerName = playerName; this.timestamp = timestamp; } @Override public void call(PlayerListener listener) { listener.onPlayerJoin(this); } } } ``` ``` -------------------------------- ### High-Performance Event Firing (Unsafe) Source: https://context7.com/florianreuth/dietrichevents2/llms.txt Use `callUnsafe()` for maximum performance in tight loops. It bypasses bounds checking and exception handling, propagating any exceptions directly to the caller. Ensure capacity and subscribers are verified beforehand. ```java import de.florianreuth.dietrichevents2.DietrichEvents2; DietrichEvents2 bus = DietrichEvents2.global(); bus.subscribe(PlayerListener.PlayerJoinEvent.ID, (PlayerListener) event -> System.out.println("Fast: " + event.playerName)); PlayerListener.PlayerJoinEvent event = new PlayerListener.PlayerJoinEvent("Alice", System.currentTimeMillis()); // Hot path — no overhead for error handling or bounds checks for (int i = 0; i < 100_000; i++) { bus.callUnsafe(PlayerListener.PlayerJoinEvent.ID, event); } ``` -------------------------------- ### Priorities Source: https://context7.com/florianreuth/dietrichevents2/llms.txt Constants for defining subscriber priority values, allowing control over the execution order of event listeners. Lower integer values indicate earlier execution. ```APIDOC ## Priorities ### Description Optional constants for subscriber priority values. Lower integer = earlier execution. `MONITOR` (Integer.MIN_VALUE) runs before all others; `FALLBACK` (Integer.MAX_VALUE) runs last. Default priority when not specified is `NORMAL` (0). ### Constants * `Priorities.MONITOR` = Integer.MIN_VALUE (runs first) * `Priorities.HIGHEST` = -2 * `Priorities.HIGH` = -1 * `Priorities.NORMAL` = 0 (default) * `Priorities.LOW` = 1 * `Priorities.LOWEST` = 2 * `Priorities.FALLBACK` = Integer.MAX_VALUE (runs last) ### Example ```java import de.florianreuth.dietrichevents2.Priorities; DietrichEvents2 bus = DietrichEvents2.global(); bus.subscribe(PlayerListener.PlayerJoinEvent.ID, authChecker, Priorities.HIGHEST); bus.subscribe(PlayerListener.PlayerJoinEvent.ID, mainLogic, Priorities.NORMAL); bus.subscribe(PlayerListener.PlayerJoinEvent.ID, auditTrailer, Priorities.MONITOR); // Execution order: auditTrailer → authChecker → mainLogic ``` ``` -------------------------------- ### Querying subscription status Source: https://context7.com/florianreuth/dietrichevents2/llms.txt Utility methods to inspect the current subscriber state. `hasSubscriber(id)` checks if any listeners exist, `isSubscriber(id, object)` checks for a specific listener using identity, and `getSubscribers(id)` returns the raw listener array or null. ```java import de.florianreuth.dietrichevents2.DietrichEvents2; DietrichEvents2 bus = DietrichEvents2.global(); PlayerListener handler = event -> {}; bus.subscribe(PlayerListener.PlayerJoinEvent.ID, handler); boolean hasAny = bus.hasSubscriber(PlayerListener.PlayerJoinEvent.ID); // true boolean isRegistered = bus.isSubscriber(PlayerListener.PlayerJoinEvent.ID, handler); // true Object[] all = bus.getSubscribers(PlayerListener.PlayerJoinEvent.ID); // [handler] bus.unsubscribeAll(PlayerListener.PlayerJoinEvent.ID); Object[] none = bus.getSubscribers(PlayerListener.PlayerJoinEvent.ID); // null ``` -------------------------------- ### call(int id, AbstractEvent event) Source: https://context7.com/florianreuth/dietrichevents2/llms.txt Safely fires an event. It catches any Throwable thrown by a subscriber and forwards it to the configured errorHandler. If the event ID is out of bounds (no subscribers registered), it silently skips. ```APIDOC ## `call(int id, AbstractEvent event)` — Firing an Event (Safe) The recommended dispatch method for production use. Catches any `Throwable` thrown by a subscriber and forwards it to the configured `errorHandler`. Silently skips if the event ID is out of bounds (no subscribers registered yet). ### Method `call` ### Parameters #### Path Parameters - **id** (int) - Required - The unique identifier for the event. - **event** (AbstractEvent) - Required - The event object to be dispatched. ### Request Example ```java import de.florianreuth.dietrichevents2.DietrichEvents2; DietrichEvents2 bus = new DietrichEvents2(32, t -> { System.err.println("Caught in handler: " + t.getMessage()); }); bus.subscribe(PlayerListener.PlayerJoinEvent.ID, (PlayerListener) event -> { throw new RuntimeException("Something went wrong"); }); // call() catches the exception and routes it to the error handler — does not throw bus.call(PlayerListener.PlayerJoinEvent.ID, new PlayerListener.PlayerJoinEvent("Bob", System.currentTimeMillis())); // Output: Caught in handler: Something went wrong ``` ``` -------------------------------- ### Call an Event with Global Error Handling Source: https://github.com/florianreuth/dietrichevents2/blob/main/README.md Invokes an event using the global event system with default error handling. This method is suitable for most general use cases. ```java // There are multiple call methods which can be used depending on the situation: // - callUnsafe() -> Calls the event without any sanity // - callExceptionally() -> Calls the event without error handling // - call() -> Calls the event with global error handling // - callBreakable() -> Calls the event with error handling for every listener and supports // BreakableException to be thrown (also does resize) DietrichEvents2.global().call(ExampleEvent.ID, new ExampleEvent("Hello World!")); ``` -------------------------------- ### callUnsafe(int id, AbstractEvent event) Source: https://context7.com/florianreuth/dietrichevents2/llms.txt Fires an event with maximum performance by skipping bounds checking and exception handling. Any exception thrown by a subscriber propagates directly to the caller. Use only in performance-critical sections where capacity and subscribers are pre-verified. ```APIDOC ## `callUnsafe(int id, AbstractEvent event)` — Firing an Event (Maximum Performance) Dispatches the event with no bounds checking and no exception handling. Any exception thrown by a subscriber propagates directly to the caller. Use only in tight loops where you have verified capacity and subscribers in advance and need maximum throughput. ### Method `callUnsafe` ### Parameters #### Path Parameters - **id** (int) - Required - The unique identifier for the event. - **event** (AbstractEvent) - Required - The event object to be dispatched. ### Request Example ```java import de.florianreuth.dietrichevents2.DietrichEvents2; DietrichEvents2 bus = DietrichEvents2.global(); bus.subscribe(PlayerListener.PlayerJoinEvent.ID, (PlayerListener) event -> System.out.println("Fast: " + event.playerName)); PlayerListener.PlayerJoinEvent event = new PlayerListener.PlayerJoinEvent("Alice", System.currentTimeMillis()); // Hot path — no overhead for error handling or bounds checks for (int i = 0; i < 100_000; i++) { bus.callUnsafe(PlayerListener.PlayerJoinEvent.ID, event); } ``` ``` -------------------------------- ### Safe Event Firing with Error Handling Source: https://context7.com/florianreuth/dietrichevents2/llms.txt Use `call()` for production use. It catches `Throwable` from subscribers and forwards them to a configured `errorHandler`. It silently skips if the event ID is out of bounds. ```java import de.florianreuth.dietrichevents2.DietrichEvents2; DietrichEvents2 bus = new DietrichEvents2(32, t -> { System.err.println("Caught in handler: " + t.getMessage()); }); bus.subscribe(PlayerListener.PlayerJoinEvent.ID, (PlayerListener) event -> { throw new RuntimeException("Something went wrong"); }); // call() catches the exception and routes it to the error handler — does not throw bus.call(PlayerListener.PlayerJoinEvent.ID, new PlayerListener.PlayerJoinEvent("Bob", System.currentTimeMillis())); // Output: Caught in handler: Something went wrong ``` -------------------------------- ### Subscribe Listeners to Events Source: https://context7.com/florianreuth/dietrichevents2/llms.txt Register listeners using event IDs. Lambda expressions can be used for functional interfaces. Subscribers are ordered by priority (lower integer = earlier execution). Multiple events can be subscribed at once. ```java import de.florianreuth.dietrichevents2.DietrichEvents2; DietrichEvents2 bus = DietrichEvents2.global(); // Subscribe a class instance public class PlayerHandler implements PlayerListener { public PlayerHandler() { bus.subscribe(PlayerListener.PlayerJoinEvent.ID, this); } @Override public void onPlayerJoin(PlayerJoinEvent event) { System.out.println("Player joined: " + event.playerName); } } // Subscribe a lambda (PlayerListener is a functional interface with one abstract method) bus.subscribe(PlayerListener.PlayerJoinEvent.ID, (PlayerListener) event -> System.out.println("Lambda: " + event.playerName)); // Subscribe to multiple events at once bus.subscribe(handler, PlayerListener.PlayerJoinEvent.ID, PlayerListener.PlayerLeaveEvent.ID); ``` -------------------------------- ### Pre-allocate Event Capacity in DietrichEvents2 Source: https://context7.com/florianreuth/dietrichevents2/llms.txt Pre-allocate capacity for a specific number of event IDs to avoid runtime resizing. This is useful when the number of distinct event types is known beforehand. ```java import de.florianreuth.dietrichevents2.DietrichEvents2; // Pre-allocate for 128 distinct event IDs to avoid automatic resizes DietrichEvents2 bus = new DietrichEvents2(128, Throwable::printStackTrace); // Or expand an existing instance at startup bus.setEventCapacity(256); // Now IDs 0–255 can be used without triggering automatic resizing bus.subscribe(255, someHighIdListener); ``` -------------------------------- ### Using Lifecycle State Enum for Event Phases Source: https://context7.com/florianreuth/dietrichevents2/llms.txt An optional enum providing semantic names for event lifecycle phases. Used by convention to distinguish multiple events in the same logical operation (e.g., `PRE` for before, `POST` for after). ```java import de.florianreuth.dietrichevents2.StateTypes; public interface RenderListener { void onRender(RenderEvent event); class RenderEvent implements AbstractEvent { public static final int ID_PRE = 10; public static final int ID_POST = 11; public final StateTypes state; // FIRST, PRE, INTRA, POST, LAST public RenderEvent(StateTypes state) { this.state = state; } @Override public void call(RenderListener listener) { listener.onRender(this); } } } DietrichEvents2 bus = DietrichEvents2.global(); bus.subscribe(RenderListener.RenderEvent.ID_PRE, preRenderHandler); bus.subscribe(RenderListener.RenderEvent.ID_POST, postRenderHandler); bus.call(RenderListener.RenderEvent.ID_PRE, new RenderListener.RenderEvent(StateTypes.PRE)); // ... render logic ... bus.call(RenderListener.RenderEvent.ID_POST, new RenderListener.RenderEvent(StateTypes.POST)); ``` -------------------------------- ### StateTypes Source: https://context7.com/florianreuth/dietrichevents2/llms.txt An optional enum providing semantic names for event lifecycle phases. These are used by convention to distinguish different events within the same logical operation, such as 'PRE' for before and 'POST' for after. ```APIDOC ## StateTypes ### Description An optional enum providing semantic names for event lifecycle phases. Not enforced by the framework — used by convention to distinguish multiple events in the same logical operation (e.g., `PRE` for before, `POST` for after). ### Enum Values * `FIRST` * `PRE` * `INTRA` * `POST` * `LAST` ### Example ```java import de.florianreuth.dietrichevents2.StateTypes; public interface RenderListener { void onRender(RenderEvent event); class RenderEvent implements AbstractEvent { public static final int ID_PRE = 10; public static final int ID_POST = 11; public final StateTypes state; // FIRST, PRE, INTRA, POST, LAST public RenderEvent(StateTypes state) { this.state = state; } @Override public void call(RenderListener listener) { listener.onRender(this); } } } DietrichEvents2 bus = DietrichEvents2.global(); bus.subscribe(RenderListener.RenderEvent.ID_PRE, preRenderHandler); bus.subscribe(RenderListener.RenderEvent.ID_POST, postRenderHandler); bus.call(RenderListener.RenderEvent.ID_PRE, new RenderListener.RenderEvent(StateTypes.PRE)); // ... render logic ... bus.call(RenderListener.RenderEvent.ID_POST, new RenderListener.RenderEvent(StateTypes.POST)); ``` ``` -------------------------------- ### Cancellable Event (CancellableEvent) Source: https://context7.com/florianreuth/dietrichevents2/llms.txt Use `CancellableEvent` for events where the cancelled state needs to be communicated after dispatch. Calling `cancel()` sets a flag but does not interrupt dispatch; all listeners still run. Use this to signal a 'vetoed' outcome. ```java import de.florianreuth.dietrichevents2.CancellableEvent; public interface CommandListener { void onCommand(CommandEvent event); class CommandEvent extends CancellableEvent implements AbstractEvent { public static final int ID = 4; public final String command; public CommandEvent(String command) { this.command = command; } @Override public void call(CommandListener listener) { listener.onCommand(this); } } } DietrichEvents2 bus = DietrichEvents2.global(); bus.subscribe(CommandListener.CommandEvent.ID, (CommandListener) event -> { if (event.command.equals("shutdown")) { event.cancel(); // marks event as cancelled } }); CommandListener.CommandEvent event = new CommandListener.CommandEvent("shutdown"); bus.callUnsafe(CommandListener.CommandEvent.ID, event); if (event.isCancelled()) { System.out.println("Command was cancelled — not executing"); } // Output: Command was cancelled — not executing ``` -------------------------------- ### callExceptionally(int id, AbstractEvent event) Source: https://context7.com/florianreuth/dietrichevents2/llms.txt Fires an event and propagates any exceptions thrown by subscribers directly to the caller. It performs a bounds check but does not catch exceptions. Use this method when the caller is responsible for handling potential errors. ```APIDOC ## `callExceptionally(int id, AbstractEvent event)` — Firing, Propagating Exceptions Similar to `call()` but does not catch exceptions — any `Throwable` thrown by a subscriber propagates to the caller. Performs a bounds check (skips if ID is out of range). Use when the caller wants to handle errors itself. ### Method `callExceptionally` ### Parameters #### Path Parameters - **id** (int) - Required - The unique identifier for the event. - **event** (AbstractEvent) - Required - The event object to be dispatched. ### Request Example ```java import de.florianreuth.dietrichevents2.DietrichEvents2; DietrichEvents2 bus = DietrichEvents2.global(); bus.subscribe(PlayerListener.PlayerJoinEvent.ID, (PlayerListener) event -> { throw new IllegalStateException("Not ready"); }); try { bus.callExceptionally(PlayerListener.PlayerJoinEvent.ID, new PlayerListener.PlayerJoinEvent("Charlie", System.currentTimeMillis())); } catch (IllegalStateException e) { System.out.println("Caller handles: " + e.getMessage()); // Output: Caller handles: Not ready } ``` ``` -------------------------------- ### Define Custom Event with AbstractEvent Source: https://context7.com/florianreuth/dietrichevents2/llms.txt Implement AbstractEvent for custom event types. Each event must declare a unique static int ID. The type parameter T specifies the listener interface. ```java import de.florianreuth.dietrichevents2.AbstractEvent; // Define the listener interface and its nested event class together public interface PlayerListener { void onPlayerJoin(PlayerJoinEvent event); class PlayerJoinEvent implements AbstractEvent { // Each event type needs a unique ID, starting from 0 public static final int ID = 0; public final String playerName; public final long timestamp; public PlayerJoinEvent(String playerName, long timestamp) { this.playerName = playerName; this.timestamp = timestamp; } @Override public void call(PlayerListener listener) { listener.onPlayerJoin(this); } } } ``` -------------------------------- ### Static Stoppable Event (BreakableEvent) Source: https://context7.com/florianreuth/dietrichevents2/llms.txt Extend `BreakableEvent` for events that can stop their own dispatch chain by calling `stopHandling()` within a listener. Subsequent listeners are silently skipped. The event class must be static, and `call0()` must be implemented instead of `call()`. ```java import de.florianreuth.dietrichevents2.BreakableEvent; public interface PacketListener { void onPacket(PacketEvent event); class PacketEvent extends BreakableEvent { public static final int ID = 2; public final byte[] data; public PacketEvent(byte[] data) { this.data = data; } @Override public void call0(PacketListener listener) { listener.onPacket(this); } } } DietrichEvents2 bus = DietrichEvents2.global(); // First subscriber: processes and stops the chain bus.subscribe(PacketListener.PacketEvent.ID, (PacketListener) event -> { System.out.println("Handler 1: processing " + event.data.length + " bytes"); event.stopHandling(); // all subsequent listeners are skipped }); // Second subscriber: never called after stopHandling() bus.subscribe(PacketListener.PacketEvent.ID, (PacketListener) event -> System.out.println("Handler 2: this won't print")); PacketListener.PacketEvent event = new PacketListener.PacketEvent(new byte[]{1, 2, 3}); bus.callUnsafe(PacketListener.PacketEvent.ID, event); // Output: Handler 1: processing 3 bytes ``` -------------------------------- ### Unsubscribe all listeners for an event Source: https://context7.com/florianreuth/dietrichevents2/llms.txt Removes all subscribers registered under a given event ID. Useful for lifecycle transitions like scene or level unloading. ```java import de.florianreuth.dietrichevents2.DietrichEvents2; DietrichEvents2 bus = DietrichEvents2.global(); bus.subscribe(PlayerListener.PlayerJoinEvent.ID, handlerA); bus.subscribe(PlayerListener.PlayerJoinEvent.ID, handlerB); System.out.println(bus.hasSubscriber(PlayerListener.PlayerJoinEvent.ID)); // true bus.unsubscribeAll(PlayerListener.PlayerJoinEvent.ID); System.out.println(bus.hasSubscriber(PlayerListener.PlayerJoinEvent.ID)); // false System.out.println(bus.getSubscribers(PlayerListener.PlayerJoinEvent.ID)); // null ``` -------------------------------- ### Event Firing with Exception Propagation Source: https://context7.com/florianreuth/dietrichevents2/llms.txt Use `callExceptionally()` when the caller needs to handle errors. It performs a bounds check but propagates any `Throwable` from subscribers directly to the caller, unlike `call()`. ```java import de.florianreuth.dietrichevents2.DietrichEvents2; DietrichEvents2 bus = DietrichEvents2.global(); bus.subscribe(PlayerListener.PlayerJoinEvent.ID, (PlayerListener) event -> { throw new IllegalStateException("Not ready"); }); try { bus.callExceptionally(PlayerListener.PlayerJoinEvent.ID, new PlayerListener.PlayerJoinEvent("Charlie", System.currentTimeMillis())); } catch (IllegalStateException e) { System.out.println("Caller handles: " + e.getMessage()); // Output: Caller handles: Not ready } ``` -------------------------------- ### Stoppable Dispatch via Exception (BreakableException) Source: https://context7.com/florianreuth/dietrichevents2/llms.txt Use `callBreakable` to dispatch events to subscribers individually. If a subscriber throws `BreakableException`, iteration stops immediately. Other exceptions are routed to the `errorHandler`. Works with dynamically created event instances. ```java import de.florianreuth.dietrichevents2.*; public interface SearchListener { void onSearch(SearchEvent event); class SearchEvent implements AbstractEvent { public static final int ID = 3; public final String query; public String result; public SearchEvent(String query) { this.query = query; } @Override public void call(SearchListener listener) { listener.onSearch(this); } } } DietrichEvents2 bus = DietrichEvents2.global(); bus.subscribe(SearchListener.SearchEvent.ID, (SearchListener) event -> { if (event.query.equals("stop")) { throw new BreakableException(); // stops further dispatch } event.result = "found by handler 1"; }); bus.subscribe(SearchListener.SearchEvent.ID, (SearchListener) event -> event.result = "found by handler 2"); // never reached after break SearchListener.SearchEvent event = new SearchListener.SearchEvent("stop"); bus.callBreakable(SearchListener.SearchEvent.ID, event); // event.result is null — dispatch was stopped before any handler wrote to it ``` -------------------------------- ### unsubscribeAll(int id) Source: https://context7.com/florianreuth/dietrichevents2/llms.txt Removes all subscribers registered under a given event ID. This is useful for clearing all handlers for a group of events during lifecycle transitions, such as scene or level unloads. ```APIDOC ## unsubscribeAll(int id) ### Description Removes every subscriber registered under the given event ID. Useful for lifecycle transitions such as scene/level unloads where all handlers for a group of events should be reset. ### Method Signature `unsubscribeAll(int id)` ### Parameters * **id** (int) - The ID of the event for which to remove all listeners. ### Example ```java import de.florianreuth.dietrichevents2.DietrichEvents2; DietrichEvents2 bus = DietrichEvents2.global(); bus.subscribe(PlayerListener.PlayerJoinEvent.ID, handlerA); bus.subscribe(PlayerListener.PlayerJoinEvent.ID, handlerB); System.out.println(bus.hasSubscriber(PlayerListener.PlayerJoinEvent.ID)); // true bus.unsubscribeAll(PlayerListener.PlayerJoinEvent.ID); System.out.println(bus.hasSubscriber(PlayerListener.PlayerJoinEvent.ID)); // false System.out.println(bus.getSubscribers(PlayerListener.PlayerJoinEvent.ID)); // null ``` ``` -------------------------------- ### unsubscribe(int id, Object object) Source: https://context7.com/florianreuth/dietrichevents2/llms.txt Removes a single subscriber from a specific event ID using identity comparison. It's safe to call even if the listener is not subscribed. This method can also unsubscribe from multiple event IDs in a single call. ```APIDOC ## unsubscribe(int id, Object object) ### Description Removes a single subscriber from a specific event ID. Uses identity comparison (`==`). Safe to call when the listener is not subscribed (no-op). Can also unsubscribe from multiple IDs in one call. ### Method Signature `unsubscribe(int id, Object object)` ### Parameters * **id** (int) - The ID of the event to unsubscribe from. * **object** (Object) - The listener object to remove. ### Example ```java import de.florianreuth.dietrichevents2.DietrichEvents2; DietrichEvents2 bus = DietrichEvents2.global(); PlayerListener handler = event -> System.out.println("Joined: " + event.playerName); bus.subscribe(PlayerListener.PlayerJoinEvent.ID, handler); // Verify subscription System.out.println(bus.isSubscriber(PlayerListener.PlayerJoinEvent.ID, handler)); // true // Remove from one event bus.unsubscribe(PlayerListener.PlayerJoinEvent.ID, handler); System.out.println(bus.isSubscriber(PlayerListener.PlayerJoinEvent.ID, handler)); // false // Remove from multiple events at once bus.unsubscribe(handler, PlayerListener.PlayerJoinEvent.ID, PlayerListener.PlayerLeaveEvent.ID); ``` ``` -------------------------------- ### Unsubscribe a single listener from an event Source: https://context7.com/florianreuth/dietrichevents2/llms.txt Removes a specific subscriber from an event ID using identity comparison. Safe to call even if the listener is not subscribed. Can also unsubscribe from multiple IDs in one call. ```java import de.florianreuth.dietrichevents2.DietrichEvents2; DietrichEvents2 bus = DietrichEvents2.global(); PlayerListener handler = event -> System.out.println("Joined: " + event.playerName); bus.subscribe(PlayerListener.PlayerJoinEvent.ID, handler); // Verify subscription System.out.println(bus.isSubscriber(PlayerListener.PlayerJoinEvent.ID, handler)); // true // Remove from one event bus.unsubscribe(PlayerListener.PlayerJoinEvent.ID, handler); System.out.println(bus.isSubscriber(PlayerListener.PlayerJoinEvent.ID, handler)); // false // Remove from multiple events at once bus.unsubscribe(handler, PlayerListener.PlayerJoinEvent.ID, PlayerListener.PlayerLeaveEvent.ID); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.