Skip to content
On this page

Event

ll/api/event/ · Common / Server / Client

Overview

The Event module provides a publish-subscribe event system. It includes an event bus singleton, typed listeners with priority control, cancellable events, and a comprehensive set of built-in events for player actions, world changes, entities, server lifecycle, commands, and client-specific events.

Headers

HeaderDescription
ll/api/event/EventBus.hSingleton event dispatcher
ll/api/event/Event.hBase event class
ll/api/event/EventId.hEvent type identification
ll/api/event/Listener.hTyped event listener
ll/api/event/ListenerBase.hBase listener with priority
ll/api/event/Cancellable.hCancellable event mixin
ll/api/event/Emitter.hEvent emitter base
ll/api/event/DynamicListener.hRuntime listener creation
ll/api/event/MultiListener.hListen to multiple event types

Key Classes

EventBus

Singleton event dispatcher. All event publishing and subscription goes through this.

C++
namespace ll::event {
class EventBus {
public:
    static EventBus& getInstance();

    // Publish an event
    template <class T> void publish(T&& event);
    template <class T> void publish(std::string_view modName, T&& event);

    // Add/remove listeners
    template <class T> bool addListener(std::shared_ptr<Listener<T>> const& listener);
    bool removeListener(ListenerPtr const& listener);
    template <class T> bool removeListener(ListenerPtr const& listener);

    // Convenience: create and add in one call
    template <class T, class L = Listener<T>, class... Args>
    auto emplaceListener(Args&&... args);

    // Query
    template <class T> size_t getListenerCount();
    bool hasEvent(EventIdView const& eventId) const;
    bool hasListener(ListenerId id) const;

    // Set emitter factory
    template <class T> bool setEventEmitter(FactoryFn fn, std::weak_ptr<mod::Mod> mod);
};
}

Event

Abstract base class for all events.

C++
namespace ll::event {
class Event {
public:
    virtual ~Event();
    virtual void serialize(CompoundTag&) const;
    virtual void deserialize(CompoundTag const&);
    virtual EventId getId() const;
};
}

Listener<T>

Typed listener bound to a specific event type.

C++
namespace ll::event {
template <class T>
class Listener : public ListenerBase {
public:
    using event_type  = T;
    using callback_fn = std::function<void(event_type&)>;

    explicit Listener(callback_fn fn, EventPriority priority = EventPriority::Normal,
                      std::weak_ptr<mod::Mod> mod = mod::NativeMod::current());

    static std::shared_ptr<Listener> create(callback_fn fn, EventPriority priority = EventPriority::Normal,
                                             std::weak_ptr<mod::Mod> mod = mod::NativeMod::current());
};
}

EventPriority

C++
enum class EventPriority {
    Highest = 0,
    High    = 100,
    Normal  = 200,
    Low     = 300,
    Lowest  = 400,
};

Cancellable<T>

Mixin template to make an event cancellable.

C++
namespace ll::event {
template <class T>
class Cancellable : public T {
public:
    bool isCancelled();
    void setCancelled(bool cancelled);
    void cancel();
};
}

Built-in Events

Player Events [Common]

EventDescriptionCancellable
PlayerJoinEventPlayer joins the serverNo
PlayerDisconnectEventPlayer disconnectsNo
PlayerChatEventPlayer sends a chat messageYes
PlayerAttackEventPlayer attacks an entityYes
PlayerDestroyBlockEventPlayer destroys a blockYes
PlayerPlaceBlockEventPlayer places a blockYes
PlayerInteractBlockEventPlayer interacts with a blockYes
PlayerUseItemEventPlayer uses an itemYes
PlayerSwingEventPlayer swings armNo
PlayerJumpEventPlayer jumpsNo
PlayerSneakEventPlayer starts/stops sneakingNo
PlayerSprintEventPlayer starts/stops sprintingNo
PlayerPickUpItemEventPlayer picks up an itemYes
PlayerRespawnEventPlayer respawnsNo
PlayerDieEventPlayer diesNo
PlayerChangePermEventPlayer permission level changesNo
PlayerAddExperienceEventPlayer gains experienceNo

Entity Events [Common]

EventDescriptionCancellable
ActorHurtEventAn actor takes damageYes
MobDieEventA mob diesNo

World Events [Common]

EventDescriptionCancellable
LevelTickEventEach server tickNo
SpawnMobEventA mob spawnsYes
BlockChangedEventA block changesNo
FireSpreadEventFire spreadsYes

Server Events [Common]

EventDescriptionCancellable
ServerStartedEventServer has startedNo
ServerStoppingEventServer is stoppingNo

Command Events [Common]

EventDescriptionCancellable
ExecuteCommandEventA command is executedYes

Service Events [Common]

EventDescriptionCancellable
ServiceRegisterEventA service is registeredNo
ServiceUnregisterEventA service is unregisteredNo

Client Events [Client Only]

EventDescriptionCancellable
ClientJoinLevelEventClient joins a levelNo
ClientExitLevelEventClient exits a levelNo
ClientStartJoinLevelEventClient starts joining a levelNo
ClientCancelJoinLevelEventClient cancels level joinNo
KeyInputEventKeyboard inputYes
MouseInputEventMouse inputYes
BeforeUIRenderEventBefore UI renderingNo
AfterUIRenderEventAfter UI renderingNo

Usage

Listening to an Event

C++
#include "ll/api/event/EventBus.h"
#include "ll/api/event/player/PlayerJoinEvent.h"

void setupListeners() {
    auto& bus = ll::event::EventBus::getInstance();

    auto listener = bus.emplaceListener<ll::event::PlayerJoinEvent>(
        [](ll::event::PlayerJoinEvent& event) {
            // Handle player join
        }
    );
}

Listening with Priority

C++
#include "ll/api/event/EventBus.h"
#include "ll/api/event/player/PlayerChatEvent.h"

void setupPriorityListener() {
    auto& bus = ll::event::EventBus::getInstance();

    bus.emplaceListener<ll::event::PlayerChatEvent>(
        [](ll::event::PlayerChatEvent& event) {
            // This runs before Normal priority listeners
        },
        ll::event::EventPriority::High
    );
}

Cancelling an Event

C++
#include "ll/api/event/EventBus.h"
#include "ll/api/event/player/PlayerChatEvent.h"

void blockBadWords() {
    auto& bus = ll::event::EventBus::getInstance();

    bus.emplaceListener<ll::event::PlayerChatEvent>(
        [](ll::event::PlayerChatEvent& event) {
            // Cancel the event to prevent the chat message
            event.cancel();
        }
    );
}

Removing a Listener

C++
#include "ll/api/event/EventBus.h"
#include "ll/api/event/server/ServerStartedEvent.h"

void setupAndRemove() {
    auto& bus = ll::event::EventBus::getInstance();

    auto listener = bus.emplaceListener<ll::event::ServerStartedEvent>(
        [](ll::event::ServerStartedEvent&) {
            // One-time setup
        }
    );

    // Later, remove the listener
    bus.removeListener(listener);
}

Publishing a Custom Event

C++
#include "ll/api/event/Event.h"
#include "ll/api/event/EventBus.h"

// 1. Define the event (must be final)
class MyCustomEvent final : public ll::event::Event {
    std::string mData;
public:
    MyCustomEvent(std::string data) : mData(std::move(data)) {}
    std::string const& data() const { return mData; }
};

// 2. Publish it
void fireEvent() {
    MyCustomEvent event{"hello"};
    ll::event::EventBus::getInstance().publish(event);
}

// 3. Listen to it
void listenCustom() {
    ll::event::EventBus::getInstance().emplaceListener<MyCustomEvent>(
        [](MyCustomEvent& event) {
            // event.data() == "hello"
        }
    );
}

MultiListener

Listen to multiple event types with a single callback:

C++
#include "ll/api/event/MultiListener.h"
#include "ll/api/event/player/PlayerJoinEvent.h"
#include "ll/api/event/player/PlayerDisconnectEvent.h"

void setupMulti() {
    auto listener = ll::event::MultiListener<
        ll::event::PlayerJoinEvent,
        ll::event::PlayerDisconnectEvent
    >::create([](auto&& event) {
        // Called for both join and disconnect
    });

    ll::event::EventBus::getInstance().addListener(listener);
}

Platform Notes

  • Server events (ServerStartedEvent, ServerStoppingEvent): Available on both server and client builds, but only fire on the server side.
  • Client events (ClientJoinLevelEvent, KeyInputEvent, MouseInputEvent, render events): Only available in client builds (src-client/ll/api/event/).