Hooks & API
Available in: Server & Client
This concept applies to both environments with behavior adapted for each side.
Every hook is wrapped in pcall individually if one Addon's OnServiceRegistered throws, it's logged as a warning and every other Addon's hooks keep firing normally. One misbehaving Addon can't take down the rest.
The six hooks
| Hook | Signature | Fires |
|---|---|---|
Init |
(self, owl: AddonAPI) |
Once per Addon, in dependency order, before any Service/Controller starts OwlInit |
OnServiceRegistered |
(self, service: RegisteredService) |
Once per Service, as each one is registered via Owl.CreateService |
OnControllerRegistered |
(self, controller: RegisteredController) |
Once per Controller, as each one is registered |
OnFrameworkStarting |
(self) |
Right before Owl begins the OwlInit phase for Services/Controllers |
OnFrameworkStarted |
(self) |
Once every Service/Controller has completed OwlStart |
OnFrameworkDestroying |
(self) |
When Owl.Destroy() is called |
Only Init receives a second argument. Every other hook only needs self by the time OnServiceRegistered fires, your Addon already has everything Init gave it stored on self.
Hooks = {
Init = function(self, owl)
self.startedAt = os.clock()
end,
OnFrameworkStarted = function(self)
self.Logger.info("Framework fully started, %.2fs after Addon Init.", os.clock() - self.startedAt)
end,
}The AddonAPI passed to Init
owl in Init(self, owl) isn't the global Owl table it's a scoped view of it, with two members unique to your Addon layered on top of everything else Owl normally exposes:
| Member | Notes |
|---|---|
owl.Trove |
A Trove instance unique to this Addon not the framework-wide one. Clean up connections/instances here, not on the global Owl. |
owl.Logger |
Pre-prefixed with "Addon.<Name>", self.Logger.info(...) already tags its own output, no need to repeat the Addon's name in every message. |
| everything else | CreateService, CreateController, GetService, GetAddon, Reflection, Metrics, Config, Util... identical to calling them on Owl directly. |
Hooks = {
Init = function(self, owl)
self.Trove = owl.Trove
self.Logger = owl.Logger
self.Logger.info("Registered as an Owl Addon.")
end,
}
owl.GetProviderappears in theAddonAPItype but isn't implemented anywhere in the framework yet calling it will fail. Don't rely on it until it's actually wired up.
Looking up registered addons
-- > // By name
local analytics = Owl.GetAddon("AnalyticsAddon")
-- > // Every registered addon's name
for _, name in ipairs(Owl.Reflection.GetAddons()) do
print("Loaded addon:", name)
end
-- > // Diagnostics snapshot for one addon
local info = Owl.Reflection.GetAddonInfo("AnalyticsAddon")
if info then
print(string.format("%s v%s started: %s", info.Name, info.Version, tostring(info.Started)))
if info.InitError then
warn("Init failed:", info.InitError)
end
endOwl.Reflection.GetAddonInfo is the fastest way to check why an Addon didn't come up correctly InitError holds the caught error message if its Init hook threw, without you needing to go dig through server logs for the exact warning.
Where to go next
- Addons - Overview - creating and registering an Addon, Priority, and Dependencies.
- Automatic Hooks - the equivalent hook system for Services/Controllers, if you haven't seen that pattern yet.