Mod Settings - MSUTeam/MSU GitHub Wiki

Description

This system is a save-compatible, automated way of managing and displaying mod settings which allows modders to easily set up user-configuration for their mods.

It creates a Panel for your mod, accessible via the new mod options button inside the vanilla menu. It then allows you to create between 1 and 5 pages for your mod (with one used automatically by the Keybinds System if you add keybinds) to group the settings you create together. All within squirrel.

The settings are ordered by when they're added, but this can be adjusted with a sort() on the Settings property of the page.

All settings take a default value, de(serialize) automatically, and can be assigned one or more callbacks which are called when the value of the setting is changed to a new value.

These settings are automatically (de)serialized when loading/saving a game.

System Functions

Functions inside of <Mod>.ModSettings

getPanel

local panel = <Mod>.ModSettings.getPanel();

Returns the automatically created Settings Panel for the mod.

getPage

local page = <Mod>.ModSettings.getPage( _pageID );

Returns the Settings Page with the id _pageID within the panel of the mod.

addPage

<Mod>.ModSettings.addPage( _pageID, _pageName = null );
// _pageID is a string 
// _pageName is an optional string
// The arguments are passed to the SettingsPage constructor

Creates and adds a ::MSU.Class.SettingsPage to the Settings Panel of your mod. Returns the new SettingsPage.

getSetting

local mySetting = <Mod>.ModSettings.getSetting( _settingID );
// _settingID is a string

Returns the setting with ID _settingID

local allElements = <Mod>.ModSettings.getAllElementsAsArray( _filter = null );
// _filter is a class or a function

Returns all setting elements as an array. To further narrow down the results, for example if you want only settings, you can pass _filter as either a class, or a function. Example:

local allSettings = <Mod>.ModSettings.getAllElementsAsArray(::MSU.Class.AbstractSetting);
local allTrueBooleans = <Mod>.ModSettings.getAllElementsAsArray(function(_idx, _element){
    return _element.Type == "Boolean" && _element.getValue() == true
});

resetSettings

<Mod>.ModSettings.resetSettings();

Resets all settings (instances of ::MSU.Class.AbstractSetting) to their BaseValue.

hasSetting

local mySetting = <Mod>.ModSettings.hasSetting( _settingID );
// _settingID is a string

Returns a boolean based on whether <Mod> has the setting with ID _settingID

lockSetting

<Mod>.ModSettings.lockSetting( _setting, _lockReason );
// _setting can be a string or an MSU ModSetting
// _lockReason is a string

If _setting is a string it must be the id of a setting of <Mod>, in which case _setting will be set to this.getSetting(_setting). Otherwise pass a setting object as _setting. Locks _setting to the value that it currently has. Adds _lockReason to the lock reasons of _setting.

JavaScript/UI Functions

MSU settings are mirrored on the JS side of the game. This means they are easily accessible and adjustable via JavaScript with minimal performance overhead.

getSettingValue

MSU.getSettingValue (_modID, _settingsID)
// _modID and _settingID are strings

Returns the value of setting _settingID for the mod _modID.

setSettingValue

MSU.setSettingValue (_modID, _settingsID, _value)
// _modID and _settingID are strings
// _value is any acceptable value for the setting

Sets the setting _settingID for the mod _modID to _value.

Settings Panel

A Settings Panel is created for each mod. For now each mod can only have a single panel linked to it, the default name of which is the name of the Mod. To get the settings panel for your mod use

local myPanel = <Mod>.ModSettings.getPanel();
// myPanel is now a ::MSU.Class.SettingsPanel;

Adding a Settings Page to a Settings Panel

myPanel.add( _settingsPage );
// _settingsPage is a ::MSU.Class.SettingsPage

Add a Settings Page to myPanel
It is recommended to add a page using addPage

getMod

myPanel.getMod()

Returns the Mod object this setting panel belongs to.

Settings Page

A Settings Page is a container for individual Settings Elements. Each panel has UI space for 5 pages. Due to the way flags work we have not put a cap on the number of pages you can add, since different pages may only be displayed at different times. Empty pages are not displayed.

Constructor

local myPage = this.MSU.Class.SettingsPage( _id, _name = null );
// _id and _name are strings

_id must be unique for pages within a panel.

Adding a Settings Element to a Settings Page

settingsPage.addElement( _settingElement );
// _settingElement is a ::MSU.Class.SettingsElement

Add a Settings Element to settingsPage. Returns the _settingElement

settingsPage.addDivider( _id );

Returns addElement while passing a new Divider.

settingsPage.addTitle( _id, _name );

Returns addElement while passing a new Title.

settingsPage.addSpacer( _id, _width, _height);

Returns addElement while passing a new Spacer.

settingsPage.addBooleanSetting( _id, _value, _name = null );

Returns addElement while passing a new Boolean Setting.

settingsPage.addButtonSetting( _id, _value, _name = null );

Returns addElement while passing a new Button Setting.

settingsPage.addColorPickerSetting( _id, _value, _name = null );

Returns addElement while passing a new Color Picker Setting.

settingsPage.addEnumSetting( _id, _value, _array, _name = null );

Returns addElement while passing a new Enum Setting.

settingsPage.addRangeSetting( _id, _value, _min, _max, _step, _name = null );

Returns addElement while passing a new Range Setting.

settingsPage.addStringSetting( _id, _value, _name = null );

Returns addElement while passing a new String Setting.

getAllElementsAsArray

local allElements = settingsPage.getAllElementsAsArray( _filter = null );
// _filter is a class or a function

Returns all the elements of type filter in this page. See Addon getAllElementsAsArray for a description.

resetSettings

settingsPage.resetSettings();

Resets all settings (instances of ::MSU.Class.AbstractSetting) to their BaseValue.

getMod

settingsPage.getMod()

Returns the Mod object this setting page belongs to.

All setting elements are classes which inherit from ::MSU.Class.SettingsElement. Custom elements must inherit from SettingsElement or its descendants.

Set Description for Tooltip

function setDescription( _description )
// _description is a string

Sets the description for the element, shown when the player hovers over the tooltip in the UI.

Data

Every Settings Element has a generic Data table to which any key:value pairs can be passed. This table is also passed to the JS. This table can be retrieved with getData().

Flags

Settings Element flags allow for elements to show up only during certain screens.

Use the NewCampaign flag to specify that an element should show up when creating a new campaign.

Use the NewCampaignOnly flag to specify that a element should not show up except when creating a new campaign.

Adding Flags

Flags are added as key:value pairs to the Data table.

`setting.Data.NewCampaign <- true;`
`setting.Data.NewCampaignOnly <- true;`

getMod

<SettingsElement>.getMod()

Returns the Mod object this setting element belongs to.

Should not be initialized directly; used as a parents for other settings. All custom Settings should inherit from AbstractSetting.

Constructor

local doNotUse = ::MSU.Class.AbstractSetting( _id, _value, _name = null );
// _id and _name are strings
// _name defaults to _id

_id must be unique for all Settings Elements in a mod.
_value sets the default value for the Setting. During the constructor, the BaseValue of the setting will be set to _value.. (see setBaseValue and reset)

getValue

function getValue()

Returns the values of the setting.

set

function set( _value )
// _value type depends on setting

Sets the value of the setting to _value. If the setting was locked, this will print the lock reason(s) and return false. Otherwise returns true.

setBaseValue

function setBaseValue( _value, _reset = false )
// _value type depends on setting
// reset is a boolean

Sets the BaseValue of the setting to _value. The BaseValue refers to the value the setting has after it is reset. If _reset is true, will call setting.reset().

setPersistence

function setPersistence( _bool )
// _bool is a boolean

Sets whether the setting should use the Persistent Data system to save the setting across campaigns if the player is using BBParser, the value it sets is true after initialization.

Callbacks

Callbacks are functions that are passed to the setting. They are called when the setting changes or is pressed, in the case of button_setting. BEWARE: This is also the case when the setting is set due to BBParser. The game will be in the main_menu_state at this time, and things like this.World will not exist. You have to make sure that the callback function can deal with this, for example by checking the state with ::MSU.Utils.getActiveState().

There are two kinds of callbacks: BeforeChangeCallbacks and AfterChangeCallbacks. Currently, button_setting only supports BeforeChangeCallbacks.

Callbacks are called with the environment (this) being the setting they are assigned to.

addBeforeChangeCallback

function addBeforeChangeCallback( _callback )
_callback is a function with 1 parameter

In BeforeChangeCallbacks, the new value will be passed as an argument.

addAfterChangeCallback

function addAfterChangeCallback( _callback )
_callback is a function with 1 parameter

In AfterChangeCallbacks, the old value will be passed as an argument.

Callbacks Example

local mySetting = ::MSU.Class.BooleanSetting("mySetting", true);

mySetting.addBeforeChangeCallback(function ( _newValue )
{
    this.logInfo("Before change: Changing old value: " + this.getValue() + " to new value: " + _newValue);
})
mySetting.addAfterChangeCallback(function ( _oldValue )
{
    this.logInfo("After change: Changed old value: " + _oldValue + " to new value: " + this.getValue());
})

mySetting.set(false);
// Prints:
// "Before change: Changing old value: true to new value: false"
// "After change: Changed old value: true to new value: false"

Locking/Unlocking

Using locking, a setting can be prevented from being changed, either by the user or by code.

Lock

function lock( _lockReason = "" )
// _lockReason is a string

Prevents the setting from being changed by the user or by other code.
A _lockReason can be given which will show up in the tooltip.

Unlock

function unlock()

Unlocks the setting

isLocked

function isLocked()

Return true if setting is locked.
Returns false otherwise.

getLockReason

function getLockReason()

Returns the lock reason passed when calling lock().

reset

    this.reset();

Calls this.set(this.BaseValue); with _force = true.

A simple checkbox style setting.

Constructor

local myBooleanSetting = ::MSU.Class.BooleanSetting( _id, _value, _name = null )
// _id and _name are strings
// _value is a boolean
// _name defaults to _id

toggle

myBooleanSetting.toggle();

Toggles the Value of the BooleanSetting between true and false. Will call set with the default parameters.

A simple button setting.
When pressed, calls onPressedCallback(), which calls every defined callback.

Constructor

local myButtonSetting = ::MSU.Class.ButtonSetting( _id, null, _name = null )
// _id and _name are strings
// _value is inherently unused except for the Abstract Setting constructor, either pass null or some value you can use during callback
// _name defaults to _id

A color picker setting.
This setting creates a popup screen in which the user can define a rbga value,
which can be used in css definitions.

Constructor

local myColorPickerSetting = ::MSU.Class.ColorPickerSetting( _id, _value, _name = null )
// _id and _name are strings
// _value is a string of comma-separated red,green,blue,alpha values. Ex: "1,2,3,0.3". This refers to the initial rgba values. 
// _name defaults to _id

getValueAsHexString

myColorPickerSetting.getValueAsHexString();

Returns the Value of the setting as a hex string. This can be used in the ::createColor() vanilla function.

An enum setting.
Allows the user to select any value from the specified range of values passed in the array.

Constructor

local myEnumSetting = ::MSU.Class.EnumSetting( _id, _value, _valuesArray, _name = null)
// _id and _name are strings
// _value is any value from a possible selection in _valuesArray
// _valuesArray is an array of possible values for the setting

An advanced setting mostly used by the Keybinds System. Accepts user input by accepting pressed keys.

Constructor

local myKeybindSetting = ::MSU.Class.KeybindSetting( _id, _value, _name = null )
// _id, _value and _name are strings
// _name defaults to _id

A slider with a min and maximum value and allows for user values in defined step increments.

Constructor

local myRangeSetting = ::MSU.Class.RangeSetting( _id, _value, _min, _max, _step, _name = null )
// _id and _name are strings
// _value, _min, _max and _step are integers or floats
// _name defaults to _id

_value is the default value of the Range Setting.
_min is the minimum user set value.
_max is the maximum user set value.
_step is the increment size for changes to the setting.

A text box accepting any user input string.

Constructor

local myStringSetting = ::MSU.Class.StringSetting( _id, _value, _name = null )
// _id, _value and _name are strings
// _name defaults to _id

An empty spacer that can be used to space elements. A page can have multiple spacers, as long has they have different IDs.

Constructor

local mySpacer = ::MSU.Class.SettingsDivider( _id, _width, _height );
// _id is a string
// _width and _height are strings that define a valid css [width](https://developer.mozilla.org/en-US/docs/Web/CSS/width) and [height](https://developer.mozilla.org/en-US/docs/Web/CSS/height) statement. ex: "50%, "8rem"
// default width of elements: 35rem; full width without scrolling: 72 rem
// default height of elements: 8rem for full size, 4 rem for half size (boolean setting)

A horizontal line separating Mod Settings inside of a settings page. A page can have multiple dividers, as long has they have different IDs.

Constructor

local myDivider = ::MSU.Class.SettingsDivider( _id );
// _id is a string

A title inside of a settings page. A page can have multiple titles, as long has they have different IDs.

Constructor

local myTitle = ::MSU.Class.SettingsDivider( _id, _name );
// _id and _name are strings

Custom Settings

Additional Setting Types can be freely created by modders by:

  1. Creating a new setting class with a unique Type, extending Abstract Setting
  2. Defining a new JS var constructor for the setting called 'TypeSetting' where 'Type' is replaced with the Type member of the new class.
  3. Adding an unbindTooltip functino to that 'TypeSetting' var.
  4. Defining the layout of the setting in CSS.

It is recommended to look at the already present implementations as a guide.

Example

// create your mod
local yourmod = ::MSU.Class.Mod("yourmod", "1.0.0");

// create a page
local testPage = yourmod.ModSettings.addPage("Page", "Page Name ");
// add a title
testPage.addTitle("titleTest", "Test Title");
// add a divider
testPage.addDivider("dividertest");

// create a boolean setting and add a callback on change
local testBoolean = testPage.addBooleanSetting("TestBool", true, "Test Bool 1");
testBoolean.addCallback(function(_data = null)
{
	::logInfo(this.ID + " was changed to " + _data);
})

// create a boolean setting and set it to new campaign
local testBoolean2 = testPage.addBooleanSetting("TestBool2", true, "Test Bool 2");
testBoolean2.Data.NewCampaign <- true;

// create a boolean setting and set it to new campaign only
// this setting will only appear during the new campgin screen
local testBoolean3 = testPage.addBooleanSetting("TestBool3", true, "Test Bool 3");
testBoolean2.Data.NewCampaign <- true;
testBoolean3.Data.NewCampaignOnly <- true;

// create a range setting
testPage.addRangeSetting("TestRange", 100, 10, 300, 10);

// create an enum setting and lock it from changes
local testEnum = testPage.addEnumSetting("TestEnum" , "goodbye", ["hi", "hello", "goodbye"]);
testEnum.lock();

// create a spacer with the dimensions of a normal element
testPage.addSpacer("TestSpacer1", "35rem", "8rem");

// create a button setting with a callback to print out the ID when clicked
local buttonTest = testPage.addButtonSetting("TestButton", "Click Me", null);
buttonTest.addCallback(function(_data = null){
	this.logInfo("Button " + this.ID + " was pressed");
})

// create a spacer that spans the page at half height
testPage.addSpacer("TestSpacer2", "72rem", "4rem");

// create a string setting
testPage.addStringSetting("TestString", "String Test", null);

// create a color picker setting
testPage.addColorPickerSetting("testRBGA", "20,40,60,1");

// We can then get the values of a setting at any time using
local value = yourmod.ModSettings.getSetting("testEnum").getValue();
// value should be "goodbye"

With this example you should be able to create this mod panel. modsettings preview

⚠️ **GitHub.com Fallback** ⚠️