Skip to main content
Lua modules let you replace or extend any Lua function in the server without editing the original file. Each module is a self-contained .lua file that registers one or more overrides. The server loads your overrides at startup, and the original function is still accessible as super().

How Lua modules work

The module system uses an Override object to wrap an existing function. When the override runs, it sets up a closure environment where super points to the original function. This means you can call the original behavior from within your override.
You can also replace behavior entirely by omitting the super() call.

The module_utils.lua API

Every Lua module begins with require('modules/module_utils'). This loads the following API:

Module object

Helper functions

modifyInteractionEntry

Use xi.module.modifyInteractionEntry when you need to alter a quest or event that is loaded through the InteractionGlobal system. Reload the resource, apply your changes, and re-register it:
Do not hot-reload original quest files on a live server while using modifyInteractionEntry. Reloading the source file clears the cache entry and undoes your module’s changes.

Creating a Lua module

1

Create your file

Place your .lua file anywhere under modules/. The recommended location for custom modules is modules/custom/lua/.
modules/custom/lua/homepoint_heal.lua
2

Register it in init.txt

Add the file or its parent folder to modules/init.txt:
init.txt
3

Restart the server

Lua modules are loaded at server startup. Restart xi_map (or the relevant process) for your changes to take effect.

Module file structure

Every Lua module follows this pattern:

Examples

Adding a GM command

Place command files in a commands/ subfolder. The filename becomes the command name.
modules/example/commands/test.lua
Register the containing folder in init.txt:

Overriding a mob spawn

You can override per-zone mob callbacks using their dotted path:

Reverting a status effect

Override the onEffectGain callback to change what modifiers a status effect applies:

Directly modifying a global table

Not every customization requires addOverride. You can directly write to global tables if the module system just needs the values to be present at startup:

Loading order and super()

  • Overrides are applied in the order modules are listed in init.txt.
  • Each override wraps the previous version of the function, so chaining works correctly: if two modules both override the same function, both super() calls chain through.
  • Always call super() unless you intentionally want to discard the original behavior.