Phases and events
Every element in the descriptor (a bean, an auto-invoked function) carries the phase at which the runtime acts on it. The runtime walks a plugin's descriptor at lifecycle events and dispatches only the elements whose phase applies.
Phases
Phase in dev.versatia:
Phase | Applies to the events |
|---|---|
PLUGIN_START_ONLY | START |
PLUGIN_RELOAD_ONLY | RELOAD |
PLUGIN_RELOAD_OR_START | START, RELOAD |
PLUGIN_STOP | STOP |
UNSET | none; a technical "not given", never present in a descriptor |
Lifecycle events
LifecycleEvent | Triggered by |
|---|---|
START | the plugin's onEnable |
RELOAD | /versatia reload, plugin.versatiaReload() or VersatiaEngine.reload(name); see Reloading plugins |
STOP | the plugin's onDisable |
The bean scopes run at PLUGIN_START_ONLY: beans are created once and kept. The main class's
@PluginBean runs at PLUGIN_RELOAD_OR_START: at a reload it reloads the plugin's
Reloadable beans instead. @Value properties are set at
PLUGIN_RELOAD_OR_START, before the reloadable beans and the functions. Functions pick their phase per occurrence; put what reads configuration at PLUGIN_RELOAD_OR_START, so that a
reload re-reads it, and keep PLUGIN_START_ONLY for what the
server allows once. A BackgroundTask needs no phase: it begins at
the tick after the start and is restarted by every reload.
What happens at stop
When a plugin is disabled, the STOP event goes in a fixed order:
- Every coroutine of the plugin, its background tasks and what it
launched from its
PluginScope, is cancelled; the runtime runs them on the server thread until they have finished or five seconds have passed, so theirfinallyblocks are done. - The
PLUGIN_STOPfunctions run, best-effort: one that fails does not keep the others from running. - The plugin's state is dropped: its beans are closed, last created first, and the beans it exposed disappear. Bukkit then unregisters its listeners and cancels its Bukkit tasks.
A stop function can therefore use every bean, and no coroutine of the plugin runs alongside it.
With @DisableVersatiaFeatures(runBackgroundTasks = true) step 1
is left out, and the scope is cancelled only in step 3, when the beans are closed.
How an annotation declares its phase
Authors of plain plugins never touch this; it matters when you
define your own enhancement. @VersatiaEnhancement must say when
its processor runs, in exactly one of two ways:
// Fixed for every occurrence
@VersatiaEnhancement(BeanProcessors.LOCAL, enhancementPhase = Phase.PLUGIN_START_ONLY)
annotation class LocalBean
// Chosen per occurrence through a property of the annotation
@VersatiaEnhancement(LifecycleProcessors.AUTO_INVOKE, enhancementPhaseParamRefName = "phase")
annotation class AutoInvoke(val phase: Phase)
With enhancementPhaseParamRefName, the named property must exist on the annotation, be of type
Phase, and every occurrence must set it to something other than UNSET. Setting both forms or
neither is a compile error.
When a scope is inherited (@Service inherits @LocalBean), the phase is read from the occurrence
that links the two, that is from the @LocalBean written on the declaration of Service.