Surviving Mars

Surviving Mars

Not enough ratings
Mod Config Reborn Modders Guide
By SkiRich
Modders Guide for Mod Config Reborn

Mod Config Reborn is the next version of Mod Config built for the new generation of Surviving Mars starting with the Gagarin patch and Space race DLC. The code for Surviving Mars changes at this point. If you are interested in incorporating Mod Config Reborn, or migrating from Mod Config original please read the entire guide at least once. It can then serve as your reference book for future development.

Mod Config Reborn is here: Mod Config Reborn

Guide version:
v1.4 Updated April 4th, 2021 for Mod Config Reborn v2.5.5
   
Award
Favorite
Favorited
Unfavorite
Acknowledgements
A great big shout out and hearty acknowledgement goes to Waywocket, who built Mod Config way back when Surviving Mars first came out.
His foresight into the modding realm allowed modders such as myself and many others to offer "adjustment parameters" to their own mods making them rich with features that otherwise would be static in nature.
Since the inception, this mod has been an essential part of Surviving Mars and the modder community, and on behalf of the modder community, thank you for your work.
Getting Help
The community of modders for SM are a pretty tight small bunch.
Myself, Waywocket and ChoGGi can respond to any request for help on Mod Config Reborn.
Dont ask for it here on the guide though.
A special discussion forum on the Mod Config Reborn page is setup for asking for help.
Here: Mod Config Reborn Help Forum

Or if you need general modding help, feel free to join the discord where we all live:
SM Discord Channel[discord.gg]
What is Mod Config Reborn
Mod Config Reborn is the next generation of Mod Config.
The original Mod Config is here, for reference purposes: Mod Config Original
Mod Config Reborn is here: Mod Config Reborn

On the surface and under the hood
For all intents and purposes Mod Config Reborn operates identically as Mod Config Original for all the core code, but under the hood it has been modified to operate with the Gagarin patch going forward and introduces a new detection mechanism due to Davinci's lockdown.
The first release is designed to bridge the gap between Sagan and Gagarin.
The team expects to make future improvements and ongoing modifications to make the code better, slicker, and have more functionality.

Do I need to use this version?
The original Mod Config will not work with Gagarin going forward without a re-write. This is the re-write and depending on Waywockets development time, the original may or may not be updated directly.
This mod is created with both permission and feedback from a team of modders that includes Waywocket, myself and ChoGGi. We welcome critiques, feedback, feature requests and bug reports.
Please use the mods discussion forum not this guides comments to report any of those.

So what is Mod Config
If you are familiar with the windows registry, or ini files, or conf files, that is what Mod Config is.
It is a place to store variables.
You are given code tools and graphical controls to allow users of your mod to change these variables.
The mod you code then goes and fetches those variables and applies them to your code for your purposes. Simple.
Migration to Mod Config Reborn
Existing Mods
I have a mod with Mod Config Original, do I need to re-code my mod? Not much. All the function names have stayed the same, while the code behind those functions is now Gagarin compatible. So if you have that code running in your mod, you are good to go with that but read below.

What changed, what do I need to change?
The detection mechanism for Mod Config changed. That was due to Davinci's lockdown. A new mechanism is currently proposed but you can certainly code your own. We offer two examples to choose from as well as an alternative to one of those examples.

Data Migration
Data (settings inside mod config) from Mod Config and Mod Config Reborn are stored with the Mod Config environment. There is no way to directly move that data from Mod Config to Mod Config Reborn. If users changed their defaults, they will need to do it again. You should mention that in your mod's page somewhere so users are not surprised. In addition, if you update your mod to use Reborn, then you should mention that as well on the mod's page so the user understands they need the new version.
Overview of adding or migrating to Mod Config Reborn
This is the general overview of what is needed to add mod config reborn to your mod.

Setup process
  1. Decide which method of detection is needed
  2. Decide if you need to setup defaults before, during or after Mod Config Reborn loads.
  3. Decide if you need to read in settings before you start some functions of your mod.
Under the hood mechanics to get Mod Config Reborn to work
  1. Register your mod with Mod Config Reborn
  2. Define the Mod Config Reborn options you want to have for your mod
  3. Program code around those options.
Load Order of OnMsg's
The following is the load order of OnMsg's in Surviving Mars.
This is a handy reference to have so you understand where you can put code.
The details of the load order are out of scope for this guide.
If you want further information just ask.
The information is provided by ChoGGi which took the time to document the process.

Load Orders
New Game Load Order[github.com]
Load Game Load Order[github.com]
Sample Mod with All of SM's Msgs[github.com]

Coding a Basic Detection Mechanism
The following assumes a moderate level of understanding of how the game initializes. While I try and explain which method can be used, if you do not know things like OnMsg's for CityStart or NewMapLoaded or LoadGame, then you should ask.

Mod Config Reborn has a few ways you can detect if it is running.
Depending on what is needed in your mod, you may choose one or more of these or even code your own.

Basic Detection No Startup Code
Use if:
- Your mod only requires you to check if Mod Config Reborn is running.
- You do not need to execute ModConfig functions earlier than or in OnMsg.ClassesGenerate()

Notes
You can test for Mod Config Reborn after this.
Variables can be changed by other mods (even broken by other mods)
Mod Config Reborn resets the g_ModConfigLoaded variable to true when it finishes loading, you do not need to set it.

Pros and Cons
- Pro: Simplicity, simple to configure and use and less coding.
- Con: Can be broken by another mod doing it wrong.

Use the following syntax:
-- add this local variable to the top of your first lua script -- do not add this variable to any other place in code other than the top local ModConfig_id = "1542863522" local ModConfigLoaded = table.find(ModsLoaded, "steam_id", ModConfig_id) or false -- Use this somewhere in your code to test if ModConfigLoaded and ModConfig:IsReady() then -- do something -- run ModConfig functions -- set variables else -- Set your defaults if no mod config is detected. end
Why do I need ModConfig:IsReady() if you set a variable? Because the guarantee that ModConfig is loaded is the IsReady() function. The ModConfigLoaded is used to prevent testing for ModConfig:IsReady() and throwing errors in your log if Mod Config Reborn is disabled or missing.
Also note, ModConfigLoaded must be a local, you will be sorry if you set that as global and the player has another mod doing the same. That means this entire mechanism is limited to the one lua file its defined in.

Alternative Detection Mechanism
The following is an alternative to setting a local ModConfigLoaded and looking in the ModsLoaded table for a loaded mod.
Mod Config Reborn sets the g_ModConfigLoaded global variable, when its loaded and ready. The below code looks for that variable using rawget so it doesnt error out if ModConfig is missing or disabled.
The pros of this is, its faster and less code, and can be used anywhere without local variables, the cons are, nothing stops another mod from changing g_ModConfigLoaded after the fact, breaking this mechanism.
Use whichever you want.
Never set or reset g_ModConfigLoaded in your mod. If everyone follows that this method is great.
if rawget(_G, "g_ModConfigLoaded ") and ModConfig:IsReady() then -- do stuff else -- Use default settings end

Deprecated Detection Mechanism
The following no longer works since Davinci. Dont use it. It will throw errors in your log. Since Davinci, rawget on _G can only be run against the mod environment of the mod it is called from. All mod environments are sandboxed.
if rawget(_G, "ModConfig") and ModConfig:IsReady() then -- Use ModConfig:Get(...) to retrieve the settings else -- Use default settings end
Coding an Advanced Detection Mechanism
The following assumes a mature level of understanding of how the game initializes. While I try and explain which method can be used, if you do not know things like OnMsg's for CityStart or NewMapLoaded or LoadGame, then you should ask.

Mod Config Reborn has a few ways you can detect if it is running.
Depending on what is needed in your mod, you may choose one or more of these or even code your own.

Advanced Detection With Startup Code
Use if:
- Your mod requires you to check if Mod Config Reborn is running.
- You need to execute ModConfig functions earlier than OnMsg.ClassesGenerate() but this is not a requirement.
- You need to wait for CityStart(), NewMapLoaded(), LoadGame() or some other late init game function like UICity being loaded and ready.
- You want to guarantee another mod did not screw up g_ModConfigLoaded detection.
- You want to guarantee your code runs last to detect Mod Config Reborn.

Notes
You can test for Mod Config Reborn after this.
Variables can be changed by other mods (even broken by other mods) but it is less likely they will do this since your code runs late and in parallel.
Mod Config Reborn resets the g_ModConfigLoaded variable to true when it finishes loading, you do not need to set it. You can alter the local ModConfigLoaded variable declarations to use the same rawget example code in the Basic Detection Mechanism section if you wish.
IMPORTANT: always use local WaitForModConfig() -- if you do not set this function as a local then you run the risk of another mod executing your mods code and that will have error and bad effects.
If you must use a global, then call it something unique to your mod code, like adding a prefix.

Pros and Cons
Pros:
- Near guarantee that your code runs late and finds or confirms Mod Config Reborn is loaded.
- Code runs in parallel to game code on its own thread.
- Can run it separate from OnMsg functions.
- Can get fancy and slick with your own coding.
- Most flexible
Cons:
- Its coding, and lots of it. You should know what you are doing here.


How to use this code
Notice the section of lua variables. These variables should be in the first lua startup file in your mod, at the top or at the top where you call the function WaitForModConfig()
Variables
  • local mod_name - Change to equal a string value of your mod's name. It will appear in the logs.
  • local lf_print is for debugging, if you have a console mod like ECM otherwise leave false
  • local ModConfig_id = "1542863522" - this is the Mod ID for Mod Config Reloaded

Insert Code Here
There are two places to put your code. The spot that says: -- PUT YOUR MODs ModConfig CODE HERE --, you obviously put all your ModConfig:Get or Set code there, as well as any settings for mod variables.

The spot: -- PUT MOD DEFAULTS HERE OR SET THEM UP BEFORE RUNNING THIS FUNCTION ---, is where you would code your defaults if Mod Config Reborn is not loaded or detected. Since WaitForModConfig() is a separate function, you can set all your defaults elsewhere, and then run this function. Leave the defaults (if not found section) alone in that case.

Use the following code:
For the purposes of grabbing the code properly formatted, use this link: Code[github.com]
-- these variables go at the top of your lua script file -- only at the top, do not set these too far down. -- be carefull to use locals where stated local mod_name = "@MOD" -- Replace @MOD with your mods name. It will show up in the logs. local lf_print = false -- Used for debugging local TableFind = table.find local ModConfig_id = "1542863522" local ModConfigWaitThread = false local ModConfigLoaded = TableFind(ModsLoaded, "steam_id", ModConfig_id) or false -- This code is called from some other function or OnMsg -- typically OnMsg.CityStart() OnMsg.NewMapLoaded() or OnMsg.LoadGame() -- but can be called from just about any other function -- wait for mod config to load or fail out and use defaults local function WaitForModConfig() if (not ModConfigWaitThread) or (not IsValidThread(ModConfigWaitThread)) then ModConfigWaitThread = CreateRealTimeThread(function() if lf_print then print(string.format("%s WaitForModConfig Thread Started", mod_name)) end local threadlimit = 120 -- loops to wait before fail and exit thread loop while threadlimit > 0 do if ModConfigLoaded and ModConfig:IsReady() then -- if ModConfig loaded and is in ready state then break out of loop threadlimit = 0 break else threadlimit = threadlimit - 1 Sleep(500) -- Sleep 1/2 second ModConfigLoaded = TableFind(ModsLoaded, "steam_id", ModConfig_id) or false end -- if ModConfigLoaded end -- while if lf_print then print(string.format("%s WaitForModConfig Thread Continuing", mod_name)) end -- See if ModConfig is installed and any defaults changed if ModConfigLoaded and ModConfig:IsReady() then -- PUT YOUR MODs ModConfig CODE HERE -- ModLog(string.format("%s detected ModConfig running - Setup Complete", mod_name)) else -- PUT MOD DEFAULTS HERE OR SET THEM UP BEFORE RUNNING THIS FUNCTION --- if lf_print then print(string.format("**** %s - Mod Config Never Detected On Load - Using Defaults ****", mod_name)) end ModLog(string.format("**** %s - Mod Config Never Detected On Load - Using Defaults ****", mod_name)) end -- end if ModConfigLoaded if lf_print then print(string.format("%s WaitForModConfig Thread Ended", mod_name)) end end) -- thread else if lf_print then print(string.format("%s Error - WaitForModConfig Thread Never Ran", mod_name)) end ModLog(string.format("%s Error - WaitForModConfig Thread Never Ran", mod_name)) end -- check to make sure thread not running end -- WaitForModConfig
Coding a Detection Mechanism Based on Msg's
An alternative to using the two previous ways to detect Mod Config Reborn and set or get variables is to wait for a Msg from Mod Config Reborn itself, saying it is ready.

Mod Config Reborn sends the folllowing when it is finished loading and ready to use:
Msg("ModConfigReady")
All you have to do is listen for it.

How to use
Use the below code snippet to set up a listener for this message.
Add your code to the listener no need to wrap it in an if g_ModConfigLoaded and ModConfig:IsReady() since only ModConfig will ever send this message and only when ready.
If you need to setup defaults, be sure to setup your defaults somewhere else before this message is sent otherwise your defaults will override what you wrote.
Keep in mind Mod Config Reborn is ready immediately after OnMsg.ClassesGenerate() so your defaults need to be before that, if you need to set them up.

function OnMsg.ModConfigReady() -- Sent once ModConfig has finished loading and its safe to start using. -- Insert your code here -- ModConfig:Get or Set etc. end
Roll Your Own Detection Mechanism
Feel free to build your own detection mechanism if you are lua savvy.
There is no technical reason to use the examples in this document.
Here are the considerations to keep in mind when building your own mechanism.

- Mod Config Reborn is ready when ModConfig:IsReady() returns a true value.
- You cant use ModConfig:IsReady() until mod config is loaded fully.
- You cannot do any gets or sets until your mod is registered.
- You cant register anything until Mod Config Reborn is ready.
- Mod Config Reborn creates and sets g_ModConfigLoaded when it is ready, otherwise it is nil.
- If your mod loads before Mod Config Reborn you need to wait for it otherwise you will get log errors.
Prepare Older Mods for Reborn
The following describes how you can retro fit your current mods.
Since Davinci using rawget on _G is no longer an option. The sandboxed nature of the environment prohibits this.
Some modders wrote their own code to get around this, which is fine.
Remember, what you need to do is test for ModConfig:IsReady()
The problem is, if you test just for that, and the mod hasnt loaded yet or is disabled/missing, then you get errors and your code (depending on how you did it) will stop loading at that point.
You you need a variable to tell your code its ok to test.

The section - Coding a Basic Detection Mechanism - shows you the simplest way to do that. The problem with using this mechanism with the older ModConfig code is g_ModConfigLoaded never gets set to true. It is not in that code.

Dont do this
Dont set that variable outside the scope of either the basic or the advanced examples, since newer mods, once they start using Reborn, will step all over that, or, you will step all over other mods.
The variable is a global in nature.

Do this
If you want to roll your own and use original Mod Config in the interrim, make the variable a local in your code and then code whatever you want around it.

Alternatively and preferably consider using the Advanced Detection Mechanism example. This example tests for the presence of the mod if loaded by checking the games ModsLoaded registry.
You need to set the local ModConfig_id variable to the steam id of the original ModConfig which is 1340775972
This will allow you use the code example as is, and when Gagarin patch is rolled out and everyone switches to Reborn, all you need to do to make your mod work is switch the id to the Reborn id, which is 1542863522

Deprecated Detection Mechanism
The following no longer works since Davinci. Dont use it. It will throw errors in your log. Since Davinci, rawget on _G can only be run against the mod environment of the mod it is called from. All mod environments are sandboxed.
if rawget(_G, "ModConfig") and ModConfig:IsReady() then -- Use ModConfig:Get(...) to retrieve the settings else -- Use default settings end
Adding Options to Mod Config Reborn
The following has not changed from the original Mod Config.
The syntax and effects are the same.

In order to add options to the Mod Config window you must do the following:
1. Register your mod.
2. Add all the options you want for each variable.

Note
All of the following code is wrapped in the OnMsg.ModConfigReady() function.
If you used this function to setup your defaults as the alternate detection mechanism, then you will need to do one of two things. Either put all code to register and add options before your gets and sets or separate your code into two files in your mod. One file for mod register and options which must come first, and then your main code branch. You will need to create a second function OnMsg.ModConfigReady() function to add your options and it must be read into the mod before your other ModConfigReady() function.
Alternatively, you do not need to wrap these options in a OnMsg.ModConfigReady() , but they do need to be run after Mod Config Reborn is detected and ready.
If you just have one file and used either the basic or advanced way of detecting Mod Config Reborn then just do the following:

Defaults
As good programming you should always add a 'default' to each option (except notes).
When a user resets their Mod Config data the defaults you enter will be used.
If no defaults are added to options then a default will be chosen which may not be expected.

Type Defaults If You Dont Specify
number = 0
slider = 0
boolean = false
enum = first item in option


Register Your Mod and add options
The following code snippet is an example to register your mod with Mod Config Reborn and add a few options.
The full demo code can be found here to view or use ... Demo Code[github.com]
function OnMsg.ModConfigReady() -- Randomly generated number to start counting from, to generate IDs for translatable strings local StringIdBase = somelargerandomnumber-8digits or more -- Register this mod's name and description ModConfig:RegisterMod("ModConfigDemo", -- ID T{StringIdBase, "Mod Config Demo"}, -- Optional display name, defaults to ID T{StringIdBase + 1, "A demonstration of how to use Mod Config"} -- Optional description ) ModConfig:RegisterOption("ModConfigDemo", "BooleanOption", { name = T{StringIdBase + 2, "A Boolean Option"}, desc = T{StringIdBase + 3, "This is what a boolean option looks like."}, type = "boolean", default = false }) ModConfig:RegisterOption("ModConfigDemo", "EnumOption", { -- Texts can include images or other formatting name = T{ StringIdBase + 4, "<image UI/Icons/res_theoretical_research.tga> Enumerable Option"}, desc = T{ StringIdBase + 5, "This option lets the user pick from a selection of possible values." }, type = "enum", values = { {value = "string", label = "A String"}, -- All of these texts may be raw strings {value = 37, label = "A Number"}, {value = false, label = T{StringIdBase + 4, "Off"}} }, default = "string" }) end -- end function

Step By Step
  1. Create function OnMsg.ModConfigReady()
  2. Register your mod with ModConfig:RegisterMod()
  3. Add an option ex: ModConfig:RegisterOption("ModConfigDemo", "EnumOption" ...
Options Explained
After the initial ModConfig:RegisterMod() you can have any number of five different options.
See the screenshot below.
- boolean, which presents a checkbutton (thumbbutton) for on off, true/false
- enum, which presents a "page slider" of options that can be number, text or boolean.
- number, which presents a number with add remove arrows.
- note, which is just a line or paragraph of text
- slider, which is a slider representing your values from min to max.




function ModConfig:RegisterOption(mod_id, option_id, option_params)
Here is a table of options for RegisterOption
@param mod_id - The internal name of this mod @param option_id - The internal name of this option. This does not need to be globally unique, so different mods can have options with the same name.
@param option_params: name - The name of this option as presented to the user. This may be a translatable tuple like T{12345, "Option Name"}. If unset, defaults to option_id. desc - The description for this option as presented to the user.This may be a translatable tuple like T{12345, "Option Description"}. If unset, defaults to an empty string. order - The order in which the option will be shown. If unset, defaults to 1. Options with the same order will be ordered alphabetically by name. type - The type of variable this option controls. Currently 'boolean', 'enum', 'number', 'slider', and 'note' are supported. In the future this may be extended to other options. If unset, defaults to 'boolean'. values - When type is 'enum', this defines the possible values for the option, and the label shown to the user. Example: values = { {value = 1, label = "Option 1"}, {value = "foo", label = T{12345, "Foo"}}, {value = true, label = "Always"} } min, max - When type is 'number' or 'slider', these are used to set the minimum and maximum allowed values. If unset, no limits are enforced for 'number', and slider defaults to 0 and 100 respectively. step - When type is 'number', this is used to set how much the value will change when clicking the +/- buttons. If unset, defaults to 1. When type is 'slider', this sets the steps that the slider will snap to, and defaults to (max - min) / 10. label - When type is 'slider', this can optionally be used to display the current value as the user moves the slider, by passing a T{} object which uses a <value> element. Example: label = T{12345, "Set to <value>"} or label = T{12345, "<percent(value)>"} If unset, defaults to blank. default - The value to use if the user hasn't set the option.


Operations Functions
The following is a list of functions that operate on the Mod Config Reborn controls and data.
Get and Set are the primary functions most people use to get and set their variables. The rest are useful as well, but used in special cases.

ModConfig:Set
-- Set an option's value, then save. Sends the "ModConfigChanged" message when complete.
--
-- @param mod_id
-- @param option_id
-- @param value
-- @param token - An optional arbitrary variable you might want to pass in. The intention here is to
-- make it easier for you to filter messages you shouldn't be responding to; if you
-- set an option yourself you might want to pass in a token so that your
-- ModConfigChanged() handler can check for it and ignore the message.
--
-- @return The new value of the option
function ModConfig:Set(mod_id, option_id, value, token)

ModConfig:Get
-- Get the current or default value of an option.
--
-- @param mod_id
-- @param option_id
--
-- @return The current setting of the option if set, else the default if defined, else nil
function ModConfig:Get(mod_id, option_id)

ModConfig:Toggle
-- Toggle a boolean value
--
-- @param mod_id
-- @param option_id
-- @param token - As per Set()
--
-- @return The new value if the option is a boolean, else nil
function ModConfig:Toggle(mod_id, option_id, token)

ModConfig:Revert
-- Revert an option to its default value.
--
-- @param mod_id
-- @param option_id
-- @param token - As per Set()
--
-- @return The default setting of the option if defined, else nil
function ModConfig:Revert(mod_id, option_id, token)

ModConfig:GetDefault
-- Get the default value of an option.
--
-- @param mod_id
-- @param option_id
--
-- @return The default setting of the option if defined, else nil
function ModConfig:GetDefault(mod_id, option_id)
Built In OnMsg's
The following three listeners are available with Mod Config Reborn.
When these messages fire, you can intercept them and code for special cases.

function OnMsg.UIReady()
Sent once the game's UI has loaded and is ready to query or modify.

function OnMsg.ModConfigReady()
Sent once ModConfig has finished loading and it's safe to start using.

function OnMsg.ModConfigChanged(mod_id, option_id, value, old_value, token)
Sent whenever any mod option is changed.
The 'token' parameter matches the token given to ModConfig:Set(). The intention here is to make it easier for you to filter messages you shouldn't be responding to; if you set an option yourself you might want to pass in a token so that your handler can check for it and ignore the message.
Central Storage vs Local Storage of Options
New feature of Mod Config Reborn is the ability to use Central or Local storage of options values.
By default and if you omit this parameter MCR uses central storage for all values the user sets.
Modders may elect to use either central or local storage when building their mods.

Central Storage
Central storage is the default. All options you set are stored in the persistable memory space of MCR directly. That means all options move with your save game. On the HD or in cloud storage.

Local Storage
Local storage means any options you set for your mod are stored locally in a file called LocalStorage.lua, which is a game file for storing SM's options locally on your HD. This file is normally stored in the root of the AppData\Surviving Mars directory on windows, or your profile directory on other platforms.


Caveats to LocalStorage
  • Local storage is not saved within MCR's persistable memory and does not travel with your save games.
  • MCR loads all its persistable memory first and if a mod has any local storage options MCR will overwrite the working memory table with the local storage options for that mod.
  • Local storage gets written on any option change (ModConfig:Set). Consider that if you have a mod that writes changes many times. MCR also writes to its own working memory table at the same time.
  • Default values in your setup do not get written to file, they are after all the defaults and are already set in your options. However, if a user changes an option from default and then just happens to set it to the same value as default, this is written to file.
  • Local storage is read from file just once, on game load, from that point forward any ModConfig:Gets happen only in working memory.
  • Do not directly edit the LocalStorage.lua file. You run the risk of corruption that can bork other game related functions.
  • The option in Mod Config to Reset All Mod Config Data, also wipes the LocalStorage.lua file section for Mod Config.

Why use local storage?
If you like to watch your option writes while building a mod, this is handy. LocalStorage.lua is just a plain text file.
If your mod has dozens of options and you run the risk of running out of MCR persistable memory (the amount in persistable only storage is located at the top of Mod Config screen) then consider local storage.
If you use local storage for testing, dont forget to revert back to central storage.

How to setup Local Storage
Here is the function docs:
--------------------- ModConfig:RegisterMod ---------------------------------------------------------- -- mod_id : The internal name of this mod -- mod_name : The name of this mod as presented to the user. -- This may be a translatable tuple like T{12345, "Mod Name"}. If unset, defaults to mod_id. -- mod_desc : The description for this mod as presented to the user.This may be a -- translatable tuple like T{12345, "Mod Description"}. If unset, defaults to an -- empty string. -- save_loc : string - "localstorage" or "centralstorage" -- where the MCR will store the options for the registered mod -- localstorage is file based and will be in LocalStorage.lua file -- centralstorage saves the registered mods options with MCR's data function ModConfig:RegisterMod(mod_id, mod_name, mod_desc, save_loc)

Example:
-- Register this mod's name and description ModConfig:RegisterMod("MYMOD", -- ID T{StringIdBase, "MYMOD name"}, -- Optional display name, defaults to ID T{StringIdBase + 1, "MYMOD description"}, -- Optional description "localstorage" ) ... Your options follow ... ModConfig:RegisterOption ...

What it looks like:
Wrap Up
Thats it.
If this guide was handy, please VOTE UP!
2 Comments
SkiRich  [author] 4 Apr, 2021 @ 11:34am 
Modders: Please note the change to reference code for g_ModConfigLoaded now uses local ModConfigLoaded or rawget to verify. This will ensure proper inter-mod behavior.
SkiRich  [author] 11 Nov, 2018 @ 8:36pm 
Modders: Please note the change to reference code for g_ModConfigLoaded now says false instead of nil. See guide examples. This should be updated in all your mods and will help prevent errors when folks dont load ModConfig or turn it off.