Data Lifecycle

Factorio sorts mods first by dependencies then by natural sort order accounting for case (https://en.wikipedia.org/wiki/Natural_sort_order).

This describes the data flow for mods. In what order the different stages of data processing are done, what parts are available, and what's expected during each stage.

Note that Instrument Mode may be enabled for one mod to inject code for mod development tools which changes the data lifecycle for that mod.

1. The settings stage

When Factorio first starts, a single shared Lua state is created to process and collect mod setting prototype data from each mod into a global table named data. Additionally, a global table named mods exists that contains a mapping of mod name to mod version for all enabled mods.

First the settings.lua file is called for each mod. After settings.lua has been executed for all mods, the settings-updates.lua file is called for each mod and finally the settings-final-fixes.lua file is called for each mod. These 3 different phases of the settings stage allow to change settings of other mods without needing to rely on dependencies to load last. During this time there's no game instance created and the standard Lua API is not available. The data table expects a specific format for each item in the table. Missing properties will either fall back to default values or give an error indicating what's missing. Extra properties that the game isn't looking for are simply ignored.

Changes made during each stage of the settings loading are automatically tracked and a history of which mod has changed which prototype is recorded by the game. After the settings stage of loading has finished, the Lua state is discarded. Changes and functions defined during the settings stage will not carry over to any other stages.

At the end of this stage all setting prototypes are constructed and the startup settings are read from the mods directory "mod-settings.json" file.

2. The data stage

Next, a new shared Lua state is created to process and collect all other prototype data from each mod into a new global table named data. The global table named mods still exists and a global table named 'settings' is populated with all startup type mod setting values during this stage.

First the data.lua file is called for each mod. After data.lua has been executed for all mods, the data-updates.lua file is called for each mod and finally the data-final-fixes.lua file is called for each mod. These 3 different phases of the data stage allow to change data of other mods without needing to rely on dependencies to load last. During this time there's again no game instance created and the standard Lua API is not available. The data table expects a specific format for each item in the table. Missing properties will either fall back to default values or give an error indicating what's missing. Extra properties that the game isn't looking for are simply ignored.

Changes made during each stage of the data loading are automatically tracked and a history of which mod has changed which prototype is recorded by the game. After the data stage of loading has finished, the Lua state is discarded. Changes and functions defined during the data stage will not carry over to any other stages.

At the end of this stage, all prototypes are constructed and the game goes to the main menu.

3. control.lua initialization

During this stage, each mod's control.lua is loaded and executed in their own Lua instance that will be owned by that mod for the remainder of the play session. Each mod has its own Lua instance and own global table to store data. Because this is run every time a save file is created or loaded you don't need to restart the game to see changes made to the control.lua file. Simply restarting or reloading a save will re-run this stage.

During this stage access to the global, game, rendering tables is not available. The script table and the remote table are however available. Note, although the global table has not been setup if a mod does populate the table with some data it will be overwritten by any loaded data.

At the end of this stage (if loading a save file) mod data saved in the map file is loaded and the global table for each mod is restored.

4. control.lua init

Using the mod order each mod is partially setup:

During the script.on_init() event handler access to the game table is available and any and all changes deemed necessary by the mod are free to be performed without risk of breaking anything.

Note: until on_init has finished executing for a given mod (scenario scripts are also counted as a mod) the game will not raise any game events for that mod.

5. Migrations

Migrations are a way to handle prototype changes and mod data structure changes between mod versions or game versions. Migrations do have access to the full game state. Migrations are each run in the mods Lua state. If a mod doesn't have a control.lua the migration is run in a temporary Lua state that's discarded after the migration has been applied.

See: Migrations

6. control.lua load

Using the mod order each mod that had data loaded has script.on_load() called.

During the script.on_load() event handler access to the game table is not available. This handler is meant for only 3 things:

Attempting to change the contents of the global table during the script.on_load() event handler is not allowed. Doing so can lead to desyncs if the mod is used in multiplayer and will generate an error if the game detects it has been changed in any way.

7. control.lua script.on_configuration_changed()

When mods are changed (prototypes added or removed), the major game version changes, a mod version changes, a mod is removed, or a mod is added the script.on_configuration_changed() event is fired for each mod subscribed to that event.

This is the main place for handling mod internal data structure changes. Access to the global table, game table and game state are available and can be changed in any way seen fit by the mod.

Note: this is not the place to handle things such as recipe unlocks due to research changes - that is best done through migration scripts.

8. control.lua runtime:

At this stage the game is running fully and everything has been setup or loaded. Access to all tables is available in any event handler.