Event

An event is a structure that contains information regarding an action which has occured. Events are used to notify other parts of the engine that something has happened.

This pattern is useful to decouple different parts of the engine, so as to avoid situations like deeply nested functions calls, big switch or if statements, and so on.

Base Type

All events must inherit from the Event structure, and all events should be declared as structures as well.

The base Event structure is defined as follows:

#pragma once

#include "bboc/engine/event/IEvent.hpp"

namespace BBOC {
    struct Event : public IEvent {
        virtual ~Event() = default;

        virtual void translate([[maybe_unused]] Luau &context) const override {
            context.error("Unimplemented event translation method");
        }
    };
};

Tip

Declaring a constructor for the inherited event structures is not necessary, as the C++ language will automatically generate a default constructor with the constituent members of the structure as arguments.

Event Handler Types

There are two forms of event handlers declared in the engine, EventHandlerMethod and EventHandlerFunction:

#pragma once

#include "bboc/engine/event/Event.hpp"

#include <functional>

namespace BBOC {
    template<typename T>
    using EventLike = std::enable_if_t<std::is_base_of_v<Event, T>, int>;

    template<typename T, typename U, EventLike<T> = 0>
    using EventHandlerMethod = void (U::*)(const T &);

    template<typename T, EventLike<T> = 0>
    using EventHandlerFunction = std::function<void(const T &event)>;

    bool operator==(const EventHandlerFunction<Event> &lhs,
                    const EventHandlerFunction<Event> &rhs);
};

These two types represent member functions and lambda/free functions, respectively, and can be used interchangeably to handle events emitted to the event bus during event subscribing.

Tip

It is recommended to use EventHandlerMethod over EventHandlerFunction when possible, as this will make the implementation more maintainable, readable and easier to understand.

Miscellaneous Details

The EventLike using directive is used by some member functions of the EventBus class to determine if the type passed as a template argument is inheriting the Event structure.

The bool operator== declaration is used to enable std::find during event subscribing and unsubscribing, and should not be used externally by end users. This is yet another example of advocation against the use of using namespace in most cases.

Example

The following is an example of an event structure that represents a key press event on the keyboard, from the interface:

#pragma once

#include "bboc/engine/event/Event.hpp"

#include <string>

namespace BBOC {
    struct InterfaceKeyPressEvent : public Event {
        InterfaceKeyPressEvent(int keyCode) :
            keyCode(keyCode) {}

        // Structures do not need to have _ as a prefix
        const int keyCode;
    };
}