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:

(Opening the application)
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 application 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 modules use our suggested names for consistency, and identification in crash reports. 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.

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.

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

It’s highly suggested that you give your mod modules names that include their owning mod’s Mod Reference. This helps with telling what module belongs to what mod when you have multiple mods loaded in the editor, and it makes them easier to identify in crash logs.

Game Instance-Bound Module (UGameInstanceModule)

Suggested Root Module Name: RootInstance_YourModReferenceHere

Suggested Submodule Name: SubInstance_MoreDetails_YourModReferenceHere

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 Root Module Name: RootMenuWorld_YourModReferenceHere

Suggested Submodule Name: SubMenuWorld_MoreDetails_YourModReferenceHere

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 Root Module Name: RootGameWorld_YourModReferenceHere

Suggested Submodule Name: SubGameWorld_MoreDetails_YourModReferenceHere

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.

Submodules

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

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

The ExampleMod demonstrates this example in its root Game World module.

When a module is spawned via SpawnChildModule it will receive all of the phases that were already received by the parent module that spawned it. In the ExampleMod example, the child module is spawned during the Initialization phase. The child module still has its Construction phase called, despite spawning later than the parent.

Using Modules for Cross-Mod Interactions

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

The root Mod Modules of each mod are accessible from other mods via 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).

In blueprints, you can retrieve the Mod Module of any mod given its Mod Reference via either Get WorldModuleManager or Get GameInstanceModuleManager (depending on the module type) and Find Module nodes, which you can then cast the output of to the specific module class.