Skip to content
Greg edited this page Mar 11, 2024 · 6 revisions

Events are the building blocks for all of Void's content; they are used for transmitting information between entities and content in handlers. Events fall into two types: Notifications which are events sent to all handlers, and Interactions which are sent only to the first handler.

Parameters

Each event has a list of parameters which are unique values used lookup handlers. At minimum one parameter must be specified and typically the first parameter is a uniquely identifable name such as the event's class name in lower underscore case.

class TestEvent(val id: String) : Event {
    override val size = 1

    override fun parameter(dispatcher: EventDispatcher, index: Int) {
        return when (index) {
            0 -> "test_event"
            1 -> id
            else -> null
        }
    }
}

Any number of parameters can be used, however it's recommended to use as few as necessary (< 5).

Emission

Events can be emitted from anywhere using the singleton Events.events.emit(dispatcher, events) but they are sent alongside an EventDispatcher which represents the Entity the event was emitted from.

As events are so commonly emitted from Entities, there is a Entity.emit(event) method to help keep code clean:

player.emit(TestEvent(id = 11))

Handlers

Handlers are code which is executed everytime an event with matching parameters is emitted.

Not all parameters must match exactly, the star glyph * can be used as a wildcard to match part of a string i.e. "amulet_of_glory_*", or by itself will act as a default and match all values, including non-strings nulls.

Events.handle<Player, TestEvent>("test_event", 4) { player ->
    player.message("Test number four.")
}

In this example the player will be sent a message only when the event emitted has an id of 4.

Events.handle<Player, TestEvent>("test_event", "*") { player ->
    player.message("Test number: $id")
}

The above example will handle all TestEvent's regardless of what id they have.

Warning

If both handlers are present and an event has an id of 4, only the handler matching 4 will be executed TestEvent.notification = false even though the second match matches all ids, an exact match will be matched first.

Advanced parameters

Often times you'll want to handle the same event being emitted from different Entities, in these cases the entity type can be added to the class name using dispatcher.key. The entities id can also be added as a parameter with dispatcher.identifier.

data class VariableSet(
    val key: String,
    val from: Any?,
    val to: Any?
) : Event {
    override val size = 5

    override fun parameter(dispatcher: EventDispatcher, index: Int) = when (index) {
        0 -> "${dispatcher.key}_set_variable" // Adding the dispatcher type to the name makes it more readable
        1 -> key
        2 -> dispatcher.identifier 
        3 -> from
        4 -> to
        else -> null
    }

}

// parameters can be of any comparable types
fun variableSet(id: String = "*", from: Any? = "*", to: Any? = "*", handler: suspend VariableSet.(Player) -> Unit) {
    // "player" is used in place of the entitiy id as players don't have ids
    Events.handle("player_set_variable", id, "player", from, to, handler = handler)
}

fun npcVariableSet(npc: String = "*", variable: String = "*", from: Any? = "*", to: Any? = "*", handler: suspend VariableSet.(NPC) -> Unit) {
    // by passing an npc id we can (optionally) match the source npcs name as well as the variable and it's values
    Events.handle("npc_set_variable", variable, npc, from, to, handler = handler)
}
Clone this wiki locally