Mod Settings - MSUTeam/MSU GitHub Wiki
- Description
- System Functions
- JavaScript/UI Functions
- Settings Panel
- Settings Page
- Settings Element
- Example
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.
Functions inside of <Mod>.ModSettings
local panel = <Mod>.ModSettings.getPanel();
Returns the automatically created Settings Panel for the mod.
local page = <Mod>.ModSettings.getPage( _pageID );
Returns the Settings Page with the id _pageID
within the panel of the mod.
<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.
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
});
<Mod>.ModSettings.resetSettings();
Resets all settings (instances of ::MSU.Class.AbstractSetting
) to their BaseValue
.
local mySetting = <Mod>.ModSettings.hasSetting( _settingID );
// _settingID is a string
Returns a boolean based on whether <Mod>
has the setting with ID _settingID
<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
.
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.
MSU.getSettingValue (_modID, _settingsID)
// _modID and _settingID are strings
Returns the value of setting _settingID
for the mod _modID
.
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
.
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;
myPanel.add( _settingsPage );
// _settingsPage is a ::MSU.Class.SettingsPage
Add a Settings Page to myPanel
It is recommended to add a page using addPage
myPanel.getMod()
Returns the Mod object this setting panel belongs to.
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.
local myPage = this.MSU.Class.SettingsPage( _id, _name = null );
// _id and _name are strings
_id
must be unique for pages within a panel.
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.
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.
settingsPage.resetSettings();
Resets all settings (instances of ::MSU.Class.AbstractSetting
) to their BaseValue
.
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.
function setDescription( _description )
// _description is a string
Sets the description for the element, shown when the player hovers over the tooltip in the UI.
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()
.
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.
Flags are added as key:value pairs to the Data table.
`setting.Data.NewCampaign <- true;`
`setting.Data.NewCampaignOnly <- true;`
<SettingsElement>.getMod()
Returns the Mod object this setting element belongs to.
Abstract Setting (extends Settings Element) (Abstract)
Should not be initialized directly; used as a parents for other settings. All custom Settings should inherit from AbstractSetting.
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)
function getValue()
Returns the values of the setting.
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
.
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()
.
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 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: BeforeChangeCallback
s and AfterChangeCallback
s. Currently, button_setting
only supports BeforeChangeCallback
s.
Callbacks are called with the environment (this
) being the setting they are assigned to.
function addBeforeChangeCallback( _callback )
_callback is a function with 1 parameter
In BeforeChangeCallback
s, the new value will be passed as an argument.
function addAfterChangeCallback( _callback )
_callback is a function with 1 parameter
In AfterChangeCallback
s, the old value will be passed as an argument.
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"
Using locking, a setting can be prevented from being changed, either by the user or by code.
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.
function unlock()
Unlocks the setting
function isLocked()
Return true if setting is locked.
Returns false otherwise.
function getLockReason()
Returns the lock reason passed when calling lock()
.
this.reset();
Calls this.set(this.BaseValue);
with _force = true
.
A simple checkbox style setting.
local myBooleanSetting = ::MSU.Class.BooleanSetting( _id, _value, _name = null )
// _id and _name are strings
// _value is a boolean
// _name defaults to _id
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.
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.
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
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.
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.
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.
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.
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.
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.
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.
local myTitle = ::MSU.Class.SettingsDivider( _id, _name );
// _id and _name are strings
Additional Setting Types can be freely created by modders by:
- Creating a new setting class with a unique
Type
, extending Abstract Setting - Defining a new JS var constructor for the setting called 'TypeSetting'
where 'Type' is replaced with the
Type
member of the new class. - Adding an unbindTooltip functino to that 'TypeSetting' var.
- Defining the layout of the setting in CSS.
It is recommended to look at the already present implementations as a guide.
// 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.