-
Notifications
You must be signed in to change notification settings - Fork 18
Initializers and finalizers
When writing modular systems, it is sometimes necessary to use a piece of code for construction of objects when the script is loaded and for cleanup of objects when the script is unloaded. While there are techniques such as lazy loading or amx_guard
that solve some of the problems, sometimes there is no other choice.
An initializer is any public function whose name starts with _pp@on_init@
. Similarly, a finalizer is any public function whose name starts with _pp@on_exit@
. There are no restrictions placed on the rest of the name. As long as the name is unique, a module (within a single script) can define any number of initializers and finalizers and they will be called when appropriate:
forward _pp@on_init@module1();
public _pp@on_init@module1()
{
print("Module loaded!");
}
forward _pp@on_exit@module1();
public _pp@on_exit@module1()
{
print("Module unloaded!");
}
If PP_SYNTAX_ON_INIT
or PP_SYNTAX_ON_EXIT
is defined, a macro can be used to simplify the definitions of these functions:
pawn_on_init[module1]
{
print("Module loaded!");
}
pawn_on_exit[module1]
{
print("Module unloaded!");
}
Notice that module1
does not have to have a meaning on its own; it just serves as a suffix for the functions to be unique.
An initializer is called before any other non-initializer function in the code, even before main
. Conversely, a finalizer is called after all other functions before the script is unloaded and the corresponding AMX instance is destroyed.
Specifically, an initializer is called as soon as both of these conditions are true:
- All native functions used by the script are registered.
- All plugins that were loaded before PawnPlus have already initialized the script.
The first condition is necessary, as the code couldn't be executed before the functions are registered. The second condition allows the user to fix potential issues with other plugins that expect AmxLoad
to be called before any native function, by placing PawnPlus after the conflicting plugins in the loading order.
To satisfy these conditions, the actual function that calls the initializers is either the hooked amx_Register
called from any place, or AmxLoad
in PawnPlus.
The actual order in which initializers are called is left to the AMX implementation to decide, they are simply called in whatever order they appear in. For the standard implementation of the AMX and the compiler, the public functions are lexicographically ordered, so adding 0
s at the beginning of the name will make it be called earlier than other initializers.
Finalizers are called as part of the AMX cleanup procedure (amx_Cleanup
), right before all plugins are informed via AmxUnload
that the AMX is destroyed (because at this point, the AMX is already dead). They are called in the exact opposite order to initializers (from the top index to 0) so if two initializers create a dependency from the order they were called in (which shouldn't be caused in proper code), the corresponding finalizers (with the same unique part of their name) will not break the dependency.