Dev:Module

Below we will explain why modules are useful and how to get started with writing a module, step by step.

= Why Modules? =

Within Unreal 3.4, a large amount of functionality has been migrated to modules, as the release process continues it is likely additional functionality will move here where possible. Moving to a more modular design has many advantages, including:


 * Permits easier selection of features for networks/users that mmay not want certain functionality present
 * Allows less hassle for upgrades by permitting all but the core functionality to be updated and reloaded independently of the main IRCd
 * Makes code more maintainable by decoupling components and enforcing a strict separation of concerns
 * Eases third party contributions through making the code more approachable.

To this end, if you’re just starting to contribute, modules are generally the place to get started.

= Getting started =

Filename and location
First of all, modules go in src/modules or one of it's subdirectories. src/modules/m_*.c are generally commands. src/modules/chanmodes/ are channel modes. src/modules/usermodes are user modes.

(TODO: table ? and where do 3rd party modules go ?)

Includes
Your module starts with a whole bunch of includes.

TODO: I though we would have "all.h" or something similar by now ? ;)

Generally, these will suffice:


 * 1) include "config.h"
 * 2) include "struct.h"
 * 3) include "common.h"
 * 4) include "sys.h"
 * 5) include "numeric.h"
 * 6) include "msg.h"
 * 7) include "proto.h"
 * 8) include "channel.h"
 * 9) include 
 * 10) include 
 * 11) include 
 * 12) include 
 * 13) include 
 * 14) ifdef _WIN32
 * 15) include 
 * 16) endif
 * 17) include 
 * 18) include "h.h"
 * 19) ifdef _WIN32
 * 20) include "version.h"
 * 21) endif

Module Header
Every UnrealIRCd module has a special structure which is created by the macro MOD_HEADER. This includes the name of the module, the version, a description, a modversion, and a symbol table that is generally NULL.

ModuleHeader MOD_HEADER(mymodule) = { &quot;mymodule&quot;, &quot;$Id$&quot;, &quot;My custom command&quot;, &quot;3.2-b8-1&quot;, NULL, };

Module Functions
For the module to actually do something there are MOD_XXX functions that will be called on test, init, load and unload.

These functions are generally the place where module authors will hook into UnrealIRCd's Module API and perform any cleanup if necessary.

If you wonder what the DLLFUNC prefix (below) is for: it's for win32 compatibility. DLLFUNC is a macro that will be replaced with the appropriate compiler specific flags to have the function exported when compiled into a .DLL.

MOD_TEST
This function is executed when the module has just been loaded. If you want to run configuration test hooks (like HOOKTYPE_CONFIGTEST and HOOKTYPE_CONFIGPOSTTEST) then you add them here. Otherwise, simply don't add a MOD_TEST function.

DLLFUNC int MOD_TEST(mymodule)(ModuleInfo *moduleInfo) {   /* Test here */ return MOD_SUCCESS; }

After your MOD_TEST function is called (and callbacks set up there being called) your module COULD be unloaded by UnrealIRCd. This would be the case if your module, or any other module, fails config tests. So normally you shouldn't allocate any structures in MOD_TEST.

Note that MOD_TEST is really just for running config tests and not for anything else. All the other initialization should go in MOD_INIT, see next.

MOD_INIT
This function is executed when the module is loaded and is responsible for doing any initial structure initialization, some hooks and callbacks are registered here, as well as registering channel and user modes.

TODO: clarify what should go in MOD_INIT and what in MOD_LOAD

DLLFUNC int MOD_INIT(mymodule)(ModuleInfo *moduleInfo) {   /* Initialization here */ return MOD_SUCCESS; }

Please keep in mind that this method should make no assumptions about the surrounding state when it is loaded: the server may have active users and channels, or it may have just been started. The module can safely assume that the system can register hooks, channel modes, user modes, structures, etc, but no other assumptions can be made safely.

MOD_LOAD
DLLFUNC int MOD_LOAD(mymodule)(int module_load) {   // Do necessary initialization for when module is loaded return MOD_SUCCESS; /* returning anything else is not really supported here */ }

The MOD_LOAD function is called when the module is fully loaded, configuration has been read (if any). All commands and user/channel modes etc. have been loaded at this point, so it's also the place to add command overrides (TODO: link).

MOD_UNLOAD
DLLFUNC int MOD_UNLOAD(mymodule)(int module_unload) {	// Perform any cleanup for unload }

The MOD_UNLOAD operation is called by the system when a module is being unloaded. You should do any cleanup of internal structures that is necessary, such as freeing memory structures, closing handles (eg: files, curl, etc). It is worth noting, to save yourself time, that hooks and any added Cmodes and Umodes, and generally all external structures will be cleaned up on exit automatically - so this is really meant to be focused on cleaning up any structures or memory you have allocated or used internally that require cleanup.

Adding commands, user modes, overrides, hook, etc..
Above you learned how to write the module skeleton and what is called when. Now it's time to learn about the Module API to actually do something useful.