Modularity Library (lia.module)
This page explains the module-loading system that powers Lilia's modular architecture.
Overview
The lia.module
library is the core system responsible for loading, managing, and initializing modules within the Lilia framework. It provides a robust module loading system that handles dependencies, permissions, submodules, and automatic file inclusion. The library maintains a registry of all loaded modules in lia.module.list
and ensures proper initialization order.
Key Features:
- Automatic Module Discovery: Scans directories for module folders and loads them automatically
- Dependency Management: Handles module dependencies and includes required files
- Permission System: Automatically registers module privileges with the admin system
- Submodule Support: Recursively loads submodules from submodules/
folders
- File Organization: Automatically includes various module components (commands, hooks, libraries, etc.)
- Schema Integration: Special handling for schema modules and preload directories
- Selective Hotreload: Only reloads edited modules during development, preserving performance
Hotreload Behavior
The module system implements an optimized hotreload mechanism that distinguishes between core framework components and modules:
What Gets Reloaded Always
Core Framework Components are always loaded during hotreload, regardless of whether they've been modified:
- Core libraries (gamemode/core/libraries/
)
- Global hooks (gamemode/core/hooks/
)
- Meta tables (gamemode/core/meta/
)
- Derma components (gamemode/core/derma/
)
- Entities (gamemode/entities/
)
- Schema configuration and items
- All shared/client/server realm files
What Gets Reloaded Selectively
Modules are only reloaded if their files have been modified since the last load:
- Individual modules in modules/
folders
- Schema modules in schema/modules/
- Preload modules in schema/preload/
- Module-specific items, hooks, libraries, and other components
Hotreload Flow
Hotreload Triggered
↓
Load Core Framework (Always)
↓
Check Module Timestamps
↓
Reload Only Edited Modules
↓
Fire Initialization Hooks
This approach ensures fast development iteration by avoiding unnecessary reloading of unchanged modules while maintaining consistency of core framework components.
Core Functions
lia.module.load
Purpose
Loads a module from a specified path, setting up its environment and processing all associated components. This function handles the complete module lifecycle including file inclusion, permission registration, dependency resolution, and hook setup.
Parameters
uniqueID
(string): Unique identifier for the module (e.g., "mainmenu", "inventory")path
(string): Filesystem path to the module directoryisSingleFile
(boolean?): Set totrue
for single-file modules (defaultfalse
)variable
(string?): Global variable name for the module (default"MODULE"
,"SCHEMA"
for schema)skipSubmodules
(boolean?): Skip loading submodules whentrue
(defaultfalse
)
Realm
Shared
Returns
- nil: This function does not return a value.
What It Does
- Environment Setup: Creates a global
MODULE
table with basic properties - File Loading: Includes the core module file (e.g.,
module.lua
) - Permission Registration: Automatically registers any defined privileges
- Dependency Resolution: Loads required dependencies and extra files
- Hook Integration: Converts module functions into hooks automatically
- Submodule Loading: Recursively loads submodules unless skipped
- Module Registration: Adds the module to
lia.module.list
for later access
Example Usage
-- Load a standard module
lia.module.load("example", "lilia/gamemode/modules/example")
-- Load a single-file module
lia.module.load("simple", "path/to/simple.lua", true)
-- Load module without submodules
lia.module.load("example", "path/to/example", false, nil, true)
lia.module.initialize
Purpose
Initializes the complete module system by loading the schema, preload modules, core framework modules, and schema-specific modules in the correct order. This is the main entry point for the module system.
Parameters
- None
Realm
Shared
Returns
- nil: This function does not return a value.
What It Does
- Schema Loading: Loads the active schema module first
- Preload Processing: Loads modules from the
preload/
directory before framework modules - Framework Modules: Loads core Lilia modules from
lilia/gamemode/modules/
- Schema Modules: Loads schema-specific modules from
schema/modules/
- Override Handling: Loads any module overrides from
schema/overrides/
- Cleanup: Removes disabled modules from the registry
- Hook Execution: Fires
InitializedSchema
andInitializedModules
hooks
Loading Order
- Schema (
schema/schema.lua
) - Preload modules (
schema/preload/*
) - Core framework modules (
lilia/gamemode/modules/*
) - Schema modules (
schema/modules/*
) - Schema overrides (
schema/overrides/*
)
Example Usage
-- Initialize the entire module system
lia.module.initialize()
-- Hook into the initialization process
hook.Add("InitializedModules", "MySetup", function()
print("All modules have been loaded!")
end)
lia.module.loadFromDir
Purpose
Scans a directory for module folders and loads each one automatically. This function is used internally by the initialization system but can also be called manually for custom module loading.
Parameters
directory
(string): Path to scan for module foldersgroup
(string?): Module group type -"schema"
or"module"
(default"module"
)skip
(table?): Table of module IDs to skip during loading
Realm
Shared
Returns
- nil: This function does not return a value.
What It Does
- Directory Scanning: Uses
file.Find
to discover module folders - Module Loading: Calls
lia.module.load
for each discovered module - Skip Logic: Respects the skip table to avoid loading specific modules
- Variable Naming: Sets appropriate global variable names based on group
Example Usage
-- Load all modules from a custom directory
lia.module.loadFromDir("custom/modules", "module")
-- Load schema modules with specific exclusions
lia.module.loadFromDir("schema/modules", "module", {test = true, debug = true})
lia.module.reloadEdited
Purpose
Reloads modules that have been edited since they were last loaded, skipping unchanged modules. This function is called automatically during hotreload operations and only affects modules, not core framework components.
Parameters
- None
Realm
Shared
Returns
- nil: This function does not return a value.
What It Does
- Selective Module Reloading: Only reloads modules whose files have been modified since last load
- Schema Handling: Checks and reloads the schema if it has been edited
- Timestamp Tracking: Updates cached modification times for reloaded modules
- Hook Execution: Fires
InitializedSchema
andInitializedModules
hooks when necessary - Item Reloading: Reloads schema items to apply changes
Important Notes
- Module-Only Operation: This function only reloads modules. Core framework components (libraries, hooks, entities, etc.) are always loaded regardless of file modification status
- Hotreload Behavior: When hotreloading the gamemode, everything except modules is loaded, and only the specific edited module is refreshed
- Performance Optimized: Skips reloading unchanged modules to improve hotreload performance
Example Usage
Hotreload Flow
Hotreload Triggered → Load Core Framework → Check Module Timestamps → Reload Only Edited Modules
↓ ↓ ↓
Always loaded: Only modules with Only affected modules
- Libraries newer timestamps get refreshed
- Hooks get checked - Schema (if edited)
- Entities - Specific modules
- Meta tables - Module items
- Derma components
lia.module.get
Purpose
Retrieves a loaded module by its unique identifier from the module registry.
Parameters
identifier
(string): The unique ID of the module to retrieve
Realm
Shared
Returns
- table | nil: The module table if found, otherwise
nil
What It Does
Provides access to the module registry (lia.module.list
) to retrieve loaded modules by their ID. This is useful for accessing module functions, data, or checking if a module is loaded.
Example Usage
-- Get a specific module
local mainMenu = lia.module.get("mainmenu")
if mainMenu then
print("Main menu module loaded:", mainMenu.name)
-- Access module functions
if mainMenu.createCharacter then
mainMenu:createCharacter()
end
end
-- Check if a module exists
if lia.module.get("inventory") then
print("Inventory system is available")
end
Module Structure
When a module is loaded, the system automatically includes various files and folders:
Automatic File Inclusion
The system automatically includes these files if they exist:
- pim.lua
→ Server realm
- config.lua
→ Shared realm
- commands.lua
→ Shared realm
- networking.lua
→ Server realm
Automatic Folder Inclusion
These folders are automatically included if they exist:
- config/
- Configuration files
- dependencies/
- Module dependencies
- libs/
- Library files
- hooks/
- Hook definitions
- libraries/
- Module-specific libraries
- commands/
- Command definitions
- netcalls/
- Network calls
- meta/
- Meta tables
- derma/
- UI components
Special Handling
- Languages: Automatically loads from
languages/
folder - Factions: Automatically loads from
factions/
folder - Classes: Automatically loads from
classes/
folder - Attributes: Automatically loads from
attributes/
folder - Entities: Automatically loads from
entities/
folder - Items: Automatically loads from
items/
folder (except for schema)
Module Properties
Each loaded module automatically receives these properties and methods:
Core Properties
uniqueID
- The module's unique identifiername
- Human-readable module namedesc
- Module descriptionauthor
- Module authorenabled
- Whether the module is enabledfolder
- Path to the module directorypath
- Full module pathloading
- Loading state flag
Built-in Methods
IsValid()
- Returns true for valid modulessetData(value, global, ignoreMap)
- Store module datagetData(default)
- Retrieve module dataModuleLoaded()
- Called after module initialization (if defined)
Hooks and Events
The module system fires several hooks during operation:
DoModuleIncludes
- Fired when including module filesInitializedSchema
- Fired after schema initializationInitializedModules
- Fired after all modules are loaded
Best Practices
- Use Preload for Overrides: Place schema-specific module overrides in
preload/
for better performance - Check Module Availability: Always check if a module exists before using it
- Follow Naming Conventions: Use descriptive unique IDs and follow the standard module structure
- Handle Dependencies: Properly declare module dependencies in the module table
- Use Hooks: Hook into module events rather than directly calling module functions