Files
Ghostship/wiki/EventSystem.md
2026-01-08 11:20:23 -06:00

2.8 KiB

Guide: Implementing New Events in the Event System

This guide explains how to define, register, call, and listen to new events, based on the RenderPauseCourseOptions implementation.


1. Define the Event Structure

Events must be defined in a header file so the system knows what data they carry.

File: src/port/hooks/list/EngineEvent.h

Use the DEFINE_EVENT macro. If the event needs to pass data to listeners (like a pointer to a boolean), define those fields inside the macro.

DEFINE_EVENT(RenderPauseCourseOptions,
    bool* render; // Data passed to listeners to modify
);

2. Register the Event

The system must register the event ID during the engine's registration phase.

File: src/port/mods/PortEnhancements.c

Add your event to the PortEnhancements_Register function:

void PortEnhancements_Register() {
    // ...
    REGISTER_EVENT(RenderPauseCourseOptions);
}

3. Call the Event in Source Code

Trigger the event in the game logic where you want the hook to occur.

File: src/game/ingame_menu.c

Use CALL_CANCELLABLE_EVENT. This fires the event and allows listeners to modify data or cancel the execution of the code block following it.

// Prepare the data
bool canPause = gMarioStates[0].action & ACT_FLAG_PAUSE_EXIT;

// Trigger the event
CALL_CANCELLABLE_EVENT(RenderPauseCourseOptions, &canPause) {
    // This block only runs if no listener cancels the event
    if (canPause) {
        render_pause_course_options(99, 93, &gDialogLineNum, 15);
    }
}

4. Create the Listener (Callback)

Implement the logic that reacts to the event. This is usually where you check for CVars or custom mod logic.

File: src/port/mods/PortEnhancements.c

void OnRenderPauseCourseOptions(IEvent* event) {
    // Only apply the logic if the specific CVar is enabled
    if (CVarGetInteger("gPauseExitWhenever", 0) == 0) {
        return;
    }

    // Cast the generic IEvent to your specific event type
    RenderPauseCourseOptions* ev = (RenderPauseCourseOptions*)event;
    
    // Modify the passed data
    *ev->render = true;
}

5. Register the Listener

Finally, tell the system to execute your callback when the event is triggered.

File: src/port/mods/PortEnhancements.c

Inside PortEnhancements_Init, use REGISTER_LISTENER:

void PortEnhancements_Init() {
    // ...
    REGISTER_LISTENER(RenderPauseCourseOptions, OnRenderPauseCourseOptions, EVENT_PRIORITY_NORMAL);
}

Summary of Macros

Macro Purpose
DEFINE_EVENT Defines the event name and its internal data structure.
REGISTER_EVENT Informs the system of the event's existence during startup.
CALL_CANCELLABLE_EVENT Executes the event and a conditional code block.
REGISTER_LISTENER Connects a specific function to an event trigger.