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#
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#
Called once when the plugin is loaded and initialized. Use this to:
- Load config values
- Initialize state
- Log a startup message
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#
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#
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#
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#
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:
on_frame(dt)— game logicon_render()— drawingon_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):
This is a valid plugin that loads and does nothing.