Skip to content

Plugin Lifecycle#

Every Xenon plugin can implement up to 7 entry points. All are optional — implement only what you need.

Entry Points#

on_get_info#

extern "C" void on_get_info(xenon::PluginInfo* info);

Called once when the host discovers the plugin. Fill in the PluginInfo struct to declare your plugin's name, flags, and dependencies. Usually handled by a macro.

When: Before any other entry point.


on_load#

extern "C" void on_load();

Called once when the plugin is loaded and initialized. Use this to:

  • Load config values
  • Initialize state
  • Log a startup message
extern "C" void on_load()
{
    g_enabled = Config::GetBool("enabled", true);
    Log("Plugin loaded!");
}

on_unload#

extern "C" void on_unload();

Called once when the plugin is being unloaded. Use this to:

  • Save config values
  • Clean up state
extern "C" void on_unload()
{
    Config::SetBool("enabled", g_enabled);
    Config::Save();
    Log("Plugin unloaded!");
}

on_frame#

extern "C" void on_frame(float deltaTime);

Called every tick. Use this for game logic, state updates, and calculations.

Parameter Type Description
deltaTime float Time in seconds since the last frame
extern "C" void on_frame(float dt)
{
    g_timer += dt;
    if (g_timer > 1.0f)
    {
        Log("One second passed");
        g_timer = 0.f;
    }
}

Warning

Do not draw in on_frame. Drawing calls are only valid during on_render.


on_render#

extern "C" void on_render();

Called every frame during the render phase. All Draw calls go here.

extern "C" void on_render()
{
    for (Entity player : Players())
    {
        if (!player.IsAlive() || !player.IsEnemy()) continue;
        Vector2 screen;
        if (WorldToScreen(player.GetBonePos(Bone::Head), screen))
            Draw::CircleFilled(screen, 5.f, Color::Red());
    }
}

on_menu#

extern "C" void on_menu();

Called when the Xenon menu is open. All ImGui calls go here.

extern "C" void on_menu()
{
    if (ImGui::CollapsingHeader("My Plugin"))
    {
        ImGui::Checkbox("Enabled", &g_enabled);
        ImGui::SliderFloat("Range", &g_range, 10.f, 200.f);
    }
}

on_hero_changed#

extern "C" void on_hero_changed(uint64_t heroPoolId);

Called when the local player's hero changes. Useful for hero-specific plugins that need to update state.

Parameter Type Description
heroPoolId uint64_t The new hero's pool ID (compare with HeroId)
extern "C" void on_hero_changed(uint64_t heroId)
{
    if (heroId == HeroId::Widowmaker)
        Log("Switched to Widowmaker");
}

Execution Order#

Each frame, the host calls entry points in this order:

  1. on_frame(dt) — game logic
  2. on_render() — drawing
  3. on_menu() — UI (only if menu is open)

on_load and on_unload are called once at plugin start/stop. on_hero_changed is called whenever the local player switches heroes. on_get_info is called during plugin discovery.

Minimal Plugin#

The absolute minimum is on_get_info (or a macro that generates it):

#include <xenon/SDK.hpp>
XENON_PLUGIN("noop", "No-Op", "Does nothing")

This is a valid plugin that loads and does nothing.