Baldur’s Gate 3 Mod Configuration Menu (BG3MCM
or MCM) is a mod that provides an in-game UI to enable players to intuitively manage mod settings as defined by mod authors. It supports various setting types, including integers, floats, checkboxes, text inputs, lists, combos/dropdowns, radio buttons, sliders, drags, and color pickers.
Most importantly, it allows authors to have a JSON-like configuration experience without spending hours writing a configuration system, and it’s easy enough to integrate that even novice modders can quickly add support for it in their own mods.
This documentation is aimed at mod authors who want to integrate their mods with MCM. If you are a player looking to use MCM to configure mods, please refer to the Nexus Mods page for instructions. This documentation provides a thorough guide on the concepts behind MCM, the features it provides to mod authors, and how to integrate MCM into your mod. You can also use the table of contents below to navigate to a desired section.
Below are listed some nice features that MCM provides to mod authors:
• Easy to use: MCM provides a simple and intuitive way to define your mod’s settings. Integrating MCM into your mod only requires creating a simple blueprint JSON file and replacing a few lines of code;
• UI without writing client-side code: MCM handles the UI for you, so you don’t have to write any client-side code or learn the IMGUI API to display your mod’s settings, since IMGUI is only available on the client side.
• Simplifies settings management: MCM takes care of saving and loading your mod’s settings automatically, so you don’t have to build an entire configuration system to manage JSON files. MCM has 9k+ lines of code so that you don’t have to deal with that.
• Instant saving and loading: Unlike the traditional way of handling settings, MCM-integrated mods update settings in real-time as they are changed, without requiring save reloads;
• Minimizes user error: MCM handles the UI and validation of settings, reducing the risk of user error when configuring your mod and encouraging them to do so safely. By skipping the need for manual editing of configuration files, a very common source of errors, users are less likely to encounter issues or need to ask how to configure your mod.
• Validation checks: MCM runs dozens of validation checks to ensure that your blueprint for integration was correctly written, while providing detailed error messages if something is wrong. It also validates the settings’ values at runtime to ensure that they respect the defined constraints, which is especially useful if JSON settings files were manually edited, something that is supported by MCM;
• Supports bespoke UI injection: MCM allows you to inject your own UI elements into the MCM UI, so you could even have a mix of MCM-generated UI and your own custom UI in the same mod. This is useful when your mod has specific features to expose in the UI that are largely unrelated to configuration;
• Notification API: Exposes an IMGUI notification API that allows mods to easily create customizable notifications with options for title, message, duration, and custom buttons.
• Cross-mod settings access: The unified config approach promoted by MCM allows for straightforward access to settings from other mods, as arbitrary implementations are mostly eliminated, facilitating compatibility and interoperability.
• Doesn’t clutter UI: MCM centralizes settings for all mods that use it, so you don’t have to worry about cluttering players’ screens with yet another IMGUI window, thinking when should it initialize, activate, or even about keybindings - and possible conflicts thereof - for showing such windows. Users will have a familiar (Noesis) button in the ESC and main menus for opening MCM.
• Furthermore, you can conditionally hide elements of your configuration based on settings’ values (by usingVisibleIf
, more details below).• Robustness: MCM has more than 40 automated server-side tests aiming to ensure that it works as expected, edge cases are handled, and errors are gracefully reported without halting the framework or game; errors from one mod won’t affect the others.
• UI agnostic: MCM was designed to be, first and foremost, a standalone configuration manager. This means that even if support for IMGUI were to be entirely removed or replaced, the underlying structure of MCM would still function correctly;
• This also means that users who can’t see the IMGUI window will still have MCM working as a config manager.• Multiple profiles: MCM has support for creating, saving, loading, and deleting multiple configuration profiles, which is useful for mod authors to separate their testing configurations while developing mods;
• Localization support: MCM supports localizing mod settings, allowing you to optionally provide translations for different languages.
On top of it all, if you currently offer multiple mod versions with different code to avoid dealing with the complexities of providing settings, you can simplify this by using a single version with MCM to introduce settings. This approach allows you to avoid creating and maintaining several different .pak releases for your mods.
You can even technically integrate MCM as an optional requirement (with hardcoded defaults or MCM values if present), although that takes a bit more effort than just adding it as a standard requirement.
First, let’s establish some important concepts so that we’re on the same page when discussing MCM. These will be used throughout the documentation:
Setting: A single configuration option that can be set by the user.
Config/Configuration/Settings: All the possible settings; the entire set of settings for a mod.
Blueprint: Defines the structure of a mod’s configuration for MCM to use (with aMCM_blueprint.json
file); written by you.
MCM Schema: Dictates the structure of the blueprint; is the ‘metaschema’; defined by MCM.
Additionally, MCM follows semantic versioning. MAJOR updates would probably mean introducing breaking changes to blueprints. I currently don’t have any MAJOR updates in mind at all.
Mod authors need to integrate their mods with MCM for their settings to appear in the UI. The subsections below go in detail about this process, but it is essentially done in two steps:
meta.lsx
file.Anything else is a matter of updating objects (if you’re storing values in tables, for example), adding custom UI (very situational) and creating hotkeys (MCM 1.18+)
It’s extremely recommended to define BG3MCM as a dependency in your
meta.lsx
file. This allows the game and mod managers to ensure that MCM is loaded before your own mod - eliminating the need to instruct users to do so manually and avoiding incorrect reports/troubleshooting when they don’t! See our guide for adding dependencies.
• Example for listing two dependencies in a meta.lsx file, one being BG3MCM; (Volition Cabinet is not required for MCM)
• You can set dependencies and their minimum required versions. It is also recommended to always set the required version (Version64
) of MCM to the version you’re using during the development of your mod.
MCM 1.14 also verifies dependencies’ versions and warn users if they have outdated versions of any mods.
The MCM_blueprint.json
file is how you specify your mod’s configuration definition; this JSON file will define how your settings are to be structured, what are their name, input type, default, etc., allowing for automatic generation of a user-friendly interface and validation of user-set values.
Recap: a blueprint is a JSON file that defines the structure of your mod’s configuration settings. It is used by MCM to generate the UI and validate the settings for you. It should be named
MCM_blueprint.json
and placed alongside your mod’smeta.lsx
file.
The MCM Schema dictates how you should structure your blueprint file, and you can get it from GitHub.
This schema file can be used to write and validate your MCM_blueprint.json
file, as it will help enforcing the intended structure of the MCM Schema in your blueprint file, ensuring that it is correctly formatted and adheres to it.
While not mandatory, it is highly recommended to set the schema up in a code editor. By adding this JSON schema entry to your settings in VSCode, for example, you can easily write and validate your blueprint files:
"json.schemas": [
{
"fileMatch": [
"MCM_blueprint*.json"
],
"url": "https://raw.githubusercontent.com/AtilioA/BG3-MCM/main/.vscode/schema.json"
}
],
* Alternatively, you can replace the url
value with the path to the schema JSON file (e.g., where you place IDEHelpers or Osi.lua files). However, only do so if you have problems with the URL above.
You can also use a service like https://www.jsonschemavalidator.net/s/cV447mjH by pasting your blueprint in the right pane; however, that can be cumbersome, and you’d have to paste the latest schema in the left to make sure you’re not using an older version. Prefer the aforementioned method.
Having the schema file set up in your IDE will help you write the blueprint file correctly, without having to guess the structure or wonder if you’re missing something. A few minor features, such as
ModName
(to replace the string used for your mod’s name) are only documented by the JSON schema.
Following are the main components of the MCM schema. Don’t stress over this too much, the schema file will guide you while writing blueprints if you have set it up, and MCM will warn you about problems during runtime.
Tabs
and Sections
:
Tabs
: Serve as top-level organizational units in the MCM menu. Each tab can exclusively contain either Sections
or standalone Settings
.
Sections
: Sub-divisions within tabs to group related settings.Settings
:
Id
: A unique string identifier for each setting, similar to a variable name in your code; used to reference the setting programmatically.Name
: The readable name of the setting as to be displayed in the MCM menu.Type
: Defines the data type and ultimately the UI representation of the setting, with supported types including int
, float
, checkbox
, text
, enum
, radio
, slider_int
, slider_float
, drag_int
, drag_float
, color_picker
, color_edit
;Default
: Specifies the initial value of the setting used during initialization or when a reset is needed. Supports various data types (integer
, number
, boolean
, string
, object
, null
) depending on the setting type.Description
and Tooltip
: Textual explanations of the setting’s purpose and usage, where Description
is visible below the setting’s widget and Tooltip
appears on hover. It is required to have at least one of these.Options
: Additional parameters that tailor the setting’s behavior, applicable to certain types like enum
, radio
, sliders and drags. This includes:
Choices
: The options to be made available for enum
and radio
types.Min
and Max
: Boundary values for types such as slider
/drag
.Multiline
: Whether the text input should be multiline, used for text
type.VisibleIf
: Allows defining a simple boolean expression that determines the visibility of a setting (also tab or section) based on the values of other settings. NOTE: this might not work in the main menu as of 1.10;Thus, the main content of the blueprint is defined in the Tabs
and Settings
properties.
Within each tab, you can define either Sections
or a list of Settings
. Sections provide a way to group related settings together under a header.
Each setting has an Id
, Name
, Type
, Default
value, and at least a Tooltip
or a Description
. Each setting Id
must be unique across the entire blueprint, and that is validated by one of the many validation checks MCM performs.
Future versions of MCM might make this structure less strict, allowing nesting tabs inside sections and vice-versa.
If your mod is symlinked, you can try out changes to your mod’s blueprint in-game by using
reset
in the console without having to restart the game every time you make a change to the blueprint file.
It’s recommended to just pick an existing blueprint from MCM-integrated mods and adapt it.
For reference, you can check out the following examples:
Auto Send Food To Camp
Smart Autosaving
Preemptively Label Containers
MCM demo (1.5.1) - OUTDATED, refer to the other examples above instead in the meantime.
After setting up the blueprint, mod authors can access the values set by the player through the MCM API from anywhere in their mod’s code.
MCM provides a convenient way for mod authors to access and modify values. As of version 1.14+, MCM introduces a global MCM
table that simplifies this process:
-- Get the value of a setting with the ID "MySetting"
local mySettingValue = MCM.Get("MySetting")
-- Set the value of a setting
MCM.Set("MySetting", newValue)
You can also listen to changes to settings values by listening to mod events like this (more on this below):
-- In your MCM-integrated mod's code
Ext.ModEvents.BG3MCM["MCM_Setting_Saved"]:Subscribe(function(payload)
if not payload or payload.modUUID ~= ModuleUUID or not payload.settingId then
return
end
if payload.settingId == "debug_level" then
_D("Setting debug level to " .. payload.value)
MyMod.DebugLevel = payload.value
end
end)
Remember, SE injects a ModuleUUID
constant that holds the value of the mod you’re writing into your runtime.
While the following code is still valid, it is recommended to use the new global MCM
table introduced in 1.14+ for easier access to settings values.
-- Get the value of a setting with the ID "MySetting". ModuleUUID has the UUID of your mod
local mySettingValue = Mods.BG3MCM.MCMAPI:GetSettingValue("MySetting", ModuleUUID)
-- Set the value of a setting
Mods.BG3MCM.MCMAPI:SetSettingValue("MySetting", newValue, ModuleUUID)
To avoid typing Mods.BG3MCM.MCMAPI:GetSettingValue
and passing your mod’s UUID every time you get/set a setting value, you can define a simple global function such as this early in your scripts:
function MCMGet(settingID)
return Mods.BG3MCM.MCMAPI:GetSettingValue(settingID, ModuleUUID)
end
-- Now, get values by calling MCMGet("setting_id")
Global functions are only accessible within your mod table, so this function won’t be causing conflicts with other MCM mods that also define it.
You can allow global usage of MCM
functions by incorporating MCM’s table early in your scripts with setmetatable(Mods[Ext.Mod.GetMod(ModuleUUID).Info.Directory], { __index = Mods.BG3MCM })
.
Otherwise, prepend Mods.BG3MCM
to all function calls.
Note that these methods are only available in the client context. They cannot be executed from server-side code, since UI-related functionality is strictly handled on the client side. If you’re trying them out with the console, run
client
before executing these methods.
MCM allows mod authors to insert custom UI elements into the MCM UI. This is only needed if you want to define custom IMGUI objects within MCM. This can be done using the InsertModMenuTab
function from MCM’s IMGUIAPI
:
Mods.BG3MCM.IMGUIAPI:InsertModMenuTab(ModuleUUID, "Tab name", function(tabHeader)
local myCustomWidget = tabHeader:AddButton("My custom widget")
myCustomWidget.OnClick = function()
_D("My custom widget was clicked!")
end
end)
This will create a new tab or insert the content at the end of an existing one.
You can define an entire tab’s content — not just a widget — and call the
InsertModMenuTab
function to insert it into the MCM window, inside the space dedicated for your mod.
• For reference, Mod Uninstaller uses both MCM-generated and custom IMGUI elements; there’s also EasyCheat that leverages theInsertModMenuTab
method to add custom logic inside MCM.
The InsertListV2SearchResults
method in the IMGUIAPI
allows mod authors to insert suggestions/‘search results’ into a list_v2
setting. This is particularly useful for providing users with dynamic suggestions based on their input as they type in the add input field of the setting.
Here’s an example of how to use the InsertListV2SearchResults
method to add the suggestions a
, b
, c
, aba
, acaca
, and abaca
to the ignore_weapons
list_v2
setting of the mod with the UUID 1c132ec4-4cd2-4c40-aeb9-ff6ee0467da8
(Auto Send Food To Camp). NOTE: In the next release, this method’s signature will be updated to settingId, searchResults, modUUID
for consistency. Sorry for the inconvenience.
Mods.BG3MCM.IMGUIAPI:InsertListV2SearchResults("1c132ec4-4cd2-4c40-aeb9-ff6ee0467da8", "ignore_weapons", {"a","b","c","aba","acaca","abaca"})
list_v2
setting;list_v2
setting for which the search results are being inserted;All searches on MCM use fuzzy matching.
• With the introduction of
ModEvents
in SE v18, the previous method for listening to MCM events was deprecated. MCM will maintain backward compatibility with the net message method for the time being.
• Prior to version 1.11, mod events were handled using a workaround that relied on net messages, which were originally designed for communication within a single mod. That approach was necessary due to the absence of a dedicated mod event system in SE at that time.
Up to 1.10, MCM used a set of channels to communicate between the client and server. Some of these can be useful for mod authors to listen to, as they can use this to update their mod’s behavior based on changes from MCM, such as when a setting is saved:
MCM_Saved_Setting
: fired whenever a setting value has been saved and written to the settings JSON file by MCM. The payload contains the setting ID and the new value. Example usage:
-- In your MCM-integrated mod's code
Ext.RegisterNetListener("MCM_Saved_Setting", function(call, payload)
local data = Ext.Json.Parse(payload)
if not data or data.modGUID ~= ModuleUUID or not data.settingId then
return
end
if data.settingId == "debug_level" then
_D("Setting debug level to " .. data.value)
MyMod.DebugLevel = data.value
end
end)
Here are some other events that can be listened to:
MCM_Setting_Reset
: Fired when a setting is reset to its default value.MCM_Server_Created_Profile
: Fired when a new profile is created.MCM_Server_Set_Profile
: Fired when a profile is set as the active one.MCM_Server_Deleted_Profile
: Fired when a profile is deleted.MCM_Mod_Tab_Added
: Fired when a mod inserts a custom tab into the MCM UI.MCM_Mod_Tab_Activated
: Fired when the user clicks a mod in the mod list in MCM’s left panel.Always verify the
modGUID
in the payload to confirm that the event pertains to the mod of interest (typically your own, which you have global access to viaModuleUUID
).
MCM_Saved_Setting
-> MCM_Setting_Saved
MCM_Reset_All_Mod_Settings
-> MCM_All_Mod_Settings_Reset
MCM_Created_Profile
-> MCM_Profile_Created
MCM_Set_Profile
-> MCM_Profile_Activated
MCM_Deleted_Profile
-> MCM_Profile_Deleted
MCM_User_Opened_Window
-> MCM_Window_Opened
MCM_User_Closed_Window
-> MCM_Window_Closed
modGUID
(payload param) -> modUUID
These changes were implemented in a backwards-compatible way.
As of 1.11, MCM uses Script Extender’s ModEvents
to communicate between different mods. This allows mod authors to subscribe to these events and implement specific behaviors in response to changes from MCM, such as when a setting is saved:
MCM_Setting_Saved
: fired whenever a setting value has been saved and written to the settings JSON file by MCM. The payload contains information such as the UUID of the mod that added this setting, the setting ID and the new value. Example usage:
-- In your MCM-integrated mod's code
Ext.ModEvents.BG3MCM["MCM_Setting_Saved"]:Subscribe(function(payload)
if not payload or payload.modUUID ~= ModuleUUID or not payload.settingId then
return
end
if payload.settingId == "debug_level" then
_D("Setting debug level to " .. payload.value)
MyMod.DebugLevel = payload.value
end
end)
Always verify the
modUUID
in the payload to confirm that the event pertains to the mod of interest (typically your own, which you have global access to viaModuleUUID
).
Here are the events that can be listened to:
Event name | Description | Payload content |
---|---|---|
MCM_Setting_Saved |
Fired whenever a setting value has been saved and written to the settings JSON file by MCM. | modUUID : The UUID of the mod settingId : The ID of the setting value : The new value of the setting oldValue : The old value of the setting |
MCM_Setting_Reset |
Fired when a setting is reset to its default value. | modUUID : The UUID of the mod settingId : The ID of the setting defaultValue : The default value of the setting |
MCM_Profile_Created |
Fired when a new profile is created. | profileName : The name of the created profile newSettings : The settings of the new profile |
MCM_Profile_Activated |
Fired when a profile is set as the active one. | profileName : The name of the active profile |
MCM_Profile_Deleted |
Fired when a profile is deleted. | profileName : The name of the deleted profile |
MCM_Mod_Tab_Added |
Fired when a mod inserts a custom tab into the MCM UI. | modUUID : The UUID of the mod tabName : The name of the tab added |
MCM_Mod_Tab_Activated |
Fired when a player clicks a mod in the mod list in MCM’s left panel. | modUUID : The UUID of the mod |
MCM_Mod_Subtab_Activated |
Fired when a subtab within a mod tab is activated. | modUUID : The UUID of the mod subtabName : The name of the activated subtab |
MCM_Window_Opened |
Fired when a player opens the MCM window. | playSound : Whether a sound should be played when the window opens. |
MCM_Window_Closed |
Fired when a player closes the MCM window. | playSound : Whether a sound should be played when the window closes. |
For the most up-to-date information, please refer to this file in the Git repository: EventChannels.lua
Validation is divided into two main categories: blueprint validation and settings validation. Blueprint validation ensures that the blueprint JSON file is correctly formatted and adheres to the MCM schema. Settings validation, on the other hand, ensures that the settings values are valid and respect the constraints defined in the blueprint.
MCM performs validation checks when:
MCM_blueprint.json
;• Settings not present in the blueprint will be removed from the settings JSON file;
• Invalid settings values will be replaced with their respective default value as specified in the blueprint;
• New settings are automatically introduced to the settings JSON file when new settings are added to the schema;
Therefore, mod authors can safely add or remove settings from the blueprint without worrying about inconsistencies in the settings JSON file.
In your blueprint, you can optionally define localization handles for various elements of the configuration, including:
This is achieved through the use of “handles” - unique identifiers that can be used to look up the localized strings, just as used by the vanilla game. For any element that you can put a user-facing string in the blueprint, you can use a handle by adding a Handles
object in the same level as the element, like this:
{
"TabId": "myTab",
"TabName": "My tab default display name",
"Handles": {
"NameHandle": "h3b019e17g75fcg48ccg8063g4de5bfcc7792"
}
},
These handles should have been listed in a loca file in your mod in order to be used;
• If handles are provided and their content can be retrieved, the localized string will be used instead of the usual name/description/tooltip;
• If the handle is not found, the usual string will be used; in the above example, it would beTabName
’s content.
The BG3 Mod Helper extension can help you create localization files and mass replace strings with handles conveniently added to your localization files.
–
(NEW IN MCM 1.16)
MCM’s Notification API allows mods to create customizable notifications within the client context, provided that MCM is installed. Notifications can be tailored with specific titles, messages, durations, and visibility preferences.
NotificationManager
is added to all mods’ global tables if MCM is loaded.
To display a success notification with default options and a custom ‘Log’ button, use the following code in the client context:
NotificationManager.ShowSuccess('notification_id', 'Test Title', 'This is a test success message', {
duration = nil, -- Duration can be set to nil for default behavior
dontShowAgainButton = true, -- Option to show a button to prevent future notifications
dontShowAgainButtonCountdownInSec = 5, -- Countdown for the 'don't show again' button
displayOnceOnly = false, -- Set to true to show the notification only once
buttons = {["Log"] = function() P("Log button clicked") end } -- Custom button with callback on click
})
The options
table (fourth param) is optional.
Analogous functions are available for other severity levels (e.g., NotificationManager.ShowError
, NotificationManager.ShowWarning
, NotificationManager.ShowInfo
).
The demo below showcases the different types of config options that can be used (all of them as of v1.5.0). The demo also shows how to insert custom UI elements into the menu and how to listen and react to MCM events.
NOTE: with the introduction of ModEvents
in SE v18, the current way of listening to MCM events will get deprecated. The demo is over 10 versions behind MCM, so please refer to other MCM mods in the meantime instead.
I hope this documentation has provided you with a clear understanding of how to integrate MCM into your mod. If you have any suggestions or encountered any points of confusion or errors, no matter how small or mundane, please let me know on the Nexus page or on Discord (BG3MC). I’m keen on ensuring MCM has excellent design and documentation. I also hope MCM enhances your development experience and provides a better experience for your users!
I’d like to thank the community again for their support and feedback, as well as the mod authors who have already integrated MCM into their mods. It’s been awesome to see what you’ve been building with it so far.