Mod Modules

Mod Modules are a system provided by SML that allows for simple hooking into the engine life-cycle at key locations important for Satisfactory modding.

This is done by creating mod module classes in your mod files which will then be automatically loaded by SML at the correct times.

Instances and Functions of these classes are then called automatically when such a life-cycle location is reached.

This system allows you as a modder more control over the initialization of your content. It is also helpful for doing cross-mod interaction.

There are currently 3 types of Mod Modules:

You can read more about each in their sections below.

Modules are not actually actors, but the Menu World and Game World modules have access to world context.

Assuming that a player launches the game, loads a save file from the main menu, exits to the main menu, then exits the game, the following will occur in order:

Execution order demonstration:

1. Game Instance-Bound Module created
2. Menu World Module created
(Loading a save file from the main menu)
3. Menu World Module destroyed
4. Game World Module created
(Returning to the main menu from the game)
5. Game World Module destroyed
6. Menu World Module created
(Exiting the game from the main menu)
7. Menu World Module destroyed
8. Game Instance-Bound Module destroyed

Module Discovery

SML is able to automatically discover the mod modules for each loaded mod.

In order to use one of these modules, just create an actor or C++ class that extends the respective module class and set the value of its "root module" boolean to true.

The actual class names you give your modules does not matter, but it is advised that your root modules use our suggested names for consistency. Every mod can have exactly one root module of each type (game instance, menu world, game world) which will be automatically registered and bootstrapped regardless of it’s name.

It is possible to create more than one module of each the 3 module types (Game Instance, Menu World, Game World). For example, you could have 2 Game Instance modules, 1 Game World module, and 1 Menu World module.

However, if you do so, you should only have one of each type marked as the Root Module. Otherwise, SML will purposely crash the game to warn of this mistake.

In order to have multiple modules of a type, you should have the Root Module that calls the other ones. In the earlier example, there would be 1 Menu World module marked as root, 1 Game World module marked as root, and 1 Game Instance module marked as root which calls the second non-root Game Instance module.

Modules can have submodules they can conditionally load, which can be used for implementing configuration-driven content registration for example, allowing modularity inside of a single mod. The example mod demonstrates this functionality in TODO.

Dispatch Lifecycle Event

The DispatchLifecycleEvent is a function that every Mod Module can override. The events are called in the different phases of the given "life-cycle locations".

Each "life-cycle location" has the following 3 phases:

  • Construction

  • Initialization

  • Post Initialization

(differentiated by the ELifecyclePhase-Enum)

When overriding this function you can use a switch statement to separate the different phases and then do your custom initialization logic.

Types of Modules

Game Instance-Bound Module (UGameInstanceModule)

Suggested Module Name: InitGameInstance

The Game Instance Module is bound to the Game Instance and lives until the game is exited. This ultimately means that it gets called once per game session. In order for this module to be called again, you’d have to re-launch Satisfactory. It will persist through world reloads and can be accessed without world context.

It also provides some standard handling of things you might need to register at this point like:

You can register them by simply adding your classes to the given variables in the constructor of your class, or the defaults of your actor if you’re using Blueprint.

The module also provides the GetGameInstance-Function which allows you to get the game instance triggering the module. You can use this capability for custom lifecycle event handling, for example.

Menu World Module (UMenuWorldModule)

Suggested Module Name: InitMenuWorld

The Menu World Module is attached to the main menu world and lives until it is exited.

This module is usually used for things that need to be initialized in the main menu. If you wanted to add something to the main menu scene, such as a menu button, this would be the place to do it.

If the user returns to the main menu, after exiting a save, for example, this Module will be called again.

Game World Module (UGameWorldModule)

Suggested Module Name: InitGameWorld

The Game World Module is attached to the normal game world in which you play Satisfactory. It lives from when a save is loaded to when the save is exited (or another save is loaded).

This module is ideally used for things that need to be initialized at the loading phase of any save or world the user actually plays the game.

If the user were to load a save file (including autosaves) this module will be called again.

It also provides some standard handling of things you might need to register at this point like:

You can register them by simply adding your classes to the given variables in the constructor of your class.

Using Modules for Cross-Mod Interactions

The root Mod Modules of each mod are accessible from other mods their mod reference. This can be used for efficiently performing cross-mod integrations. For example, you could check inside of your root module whenever mod CoolCounterMod is loaded, and then load your submodule "CoolCounterModIntegration", which will in turn access CoolCounterMod directly (because if the mod is not present, the submodule simply won’t be registered).

This functionality is demonstrated in the example mod in TODO.