Skip to content

Subscribing to Events

The PackedPacksApi instance injected on the entrypoint provides the EventBus instance which allows the posting and subscribing of events.

Registration of listeners is only permitted during the initialization inside PackedPacksInitializer#onInitialize.

Events

The following are the out-of-the-box events that you can subscribe to:

TIP

For more information, you can view the events package which includes javadocs for each event and event methods

Event Class Timing Typical Use Case
InitializeEvent.Pre Within Screen#init before everything else runs Set up widgets
InitializeEvent.Post Within Screen#init after everything else runs Adding widgets
InitializeLayoutEvent When the header and footer is being created Adding widgets to specific positions
InitializePackEntryEvent When a pack entry is created Attaching widgets to pack entries
ContextMenuEvent.Screen When the context menu is created for the screen Adding context menu items
ContextMenuEvent.Preferences When the context menu is created for the preferences sub-menu Adding preference items in the preferences sub-menu
ContextMenuEvent.PackEntry When the context menu is created for the pack entry Adding context menu items for specific packs
ClosingEvent When the screen is closing Saving data or calling commit() to apply changes
WatchEvent When a file change is detected in a pack folder Calling cancel() to prevent unecessary refreshes

Basic Registration

Create an Identifier which uniquely identifies your listeners and is used for ordering.

Register your listener with the ID using EventBus#register(Class<Event>, Identifier, Consumer<Event>).

NOTE

You cannot register multiple listeners of the same event under the same ID.

java
@Override
public void onInitialize(PackedPacksApi api) {
    Identifier id = Identifier.fromNamespaceAndPath("modid", "my_listener");

    api.eventBus().register(InitializeLayoutEvent.class, id, event -> {
        // handle event
    });
}

Ordered Registration

To ensure your listener runs after another, use the loadAfter overloads:

java
Identifier id = Identifier.fromNamespaceAndPath("modid", "my_listener");
Identifier otherId = Identifier.fromNamespaceAndPath("other_modid", "other_listener");
Identifier anotherId = Identifier.fromNamespaceAndPath("another_modid", "another_listener");

// after a single listener
api.eventBus().register(InitializeEvent.Pre.class, id, otherId, event -> {
    // handle event
});

// after multiple listeners
api.eventBus().register(InitializeEvent.Post.class, id, List.of(otherId, anotherId), event -> {
    // handle event
});

Posting Events

You can create and dispatch custom events to registered listeners. This can only be done after the initialization phase, usually inside another event handler.

For example to collect child context menu items for a parent context menu item.

java
public class PackedPacksIntegrationFoo implements PackedPacksInitializer {
    @Override
    public void onInitialize(PackedPacksApi api) {
        Identifier id = Identifier.fromNamespaceAndPath("foo", "context_menu_foo");

        api.eventBus().register(ContextMenuEvent.Screen.class, id, event -> 
            event.addItem(item -> api.eventBus().post(new FooEvent(
                event.screenContext(), 
                item.label(Component.literal("Foo")).separators())
            ))
        );
    }

    // We implement the Event marker interface to allow it to be posted and be subscribed to
    public static final class FooEvent extends ContextMenuEvent implements Event {
        private final ContextMenuItemSpec parent;

        public TestEvent(ScreenContext context, ContextMenuItemSpec parent) {
            super(context);
            this.parent = parent;
        }

        @Override
        public void addItem(Consumer<ContextMenuItemSpec> configurator) {
            this.parent.child(configurator);
        }
    }
}
java
public class PackedPacksIntegrationBar implements PackedPacksInitializer {
    @Override
    public void onInitialize(PackedPacksApi api) {
        Identifier id = Identifier.fromNamespaceAndPath("bar", "context_menu_foo");

        api.eventBus().register(PackedPacksIntegrationFoo.FooEvent.class, id, event -> 
            event.addItem(Component.literal("Bar"))
        );
    }
}