Skip to content

In Game Options Menu

Metious edited this page Feb 1, 2022 · 8 revisions

Most mods allow for users to tweak values to change the way they operate. It is possible to do this via a config file, but this requires users opening some kind of text editor and to not make typos, and is not the best experience for most users.

SMLHelper allows you to build an in-game options menu to allow users to toggle options at runtime, which you can then optionally save to disk.

Using the Abstract ConfigFile Class to Automatically Generate an In-Game Options Menu (Recommended)

Since SMLHelper 2.9 it is now possible and recommended to generate your options menu from your ConfigFile definition, as a config file and an options menu are so often used together it makes sense to allow a simple attributes-based mark-up to automate the process of setting up a menu with reduced boilerplate.

This new way of generating your options menu also takes care of loading/saving values of your ConfigFile from/to disk for you, leaving you free to implement your mods usage of these values, not worry about whether or not they've been serialized to disk appropriately.

It is still possible to define an options menu without defining a ConfigFile by using the abstract ModOptions class to manually create a menu as was common before SMLHelper 2.9, but in most cases this advanced usage is no longer necessary.

Decorating your ConfigFile with Attributes

To generate your in-game options menu from a ConfigFile, SMLHelper reads the attributes of its members to determine how to generate your menu. Full documentation for the relevant attributes can be found below.

For example, the following code would indicate to SMLHelper that the field MyInt should be represented in the options menu under the "My Options Menu" heading as a slider named "My int slider" with a range of 0-50 inclusive:

using SMLHelper.V2.Json;
using SMLHelper.V2.Options.Attributes;

/// The MenuAttribute allows us to set the title of our options menu in the "Mods" tab.
[Menu("My Options Menu")]
public class MyConfig : ConfigFile
{
    /// A SliderAttribute is used to represent a numeric value as a slider in the options menu, with a
    /// minimum and maximum value. By default, the minimum value is 0 and maximum is 100.
    /// 
    /// Here, we are setting an initial value of 25 for the slider. We are also setting the DefaultValue
    /// property so that this default can be represented by a notch in the slider.
    [Slider("My slider", 0, 50, DefaultValue = 25)]
    public int SliderValue = 25;
}

See MenuAttribute and SliderAttribute in the attribute reference for more information on these attributes.

Registering your Options Menu

After you have decorated your ConfigFile with relevant attributes as needed, to register it with SMLHelper it must be passed to the OptionsPanelHandler, as per the following example:

using QModManager.API.ModLoading;
using SMLHelper.V2.Handlers;
using Logger = QModManager.Utility.Logger;

[QModCore]
public static class MyMod
{
    internal static MyConfig Config { get; private set; }

    [QModPatch]
    public static void Patch()
    {
        Config = OptionsPanelHandler.Main.RegisterModOptions<MyConfig>();
        Logger.Log(Logger.Level.Info, "Patched successfully!");
    }
}

OptionsPanelHandler.Main.RegisterModOptions<T> returns an instance of your ConfigFile definition, which you can then access to read its fields and properties, which are updated automatically whenever the user makes changes in the menu.

By default, the values of the ConfigFile will be automatically loaded when its type is passed to RegisterModOptions<T> and saved to disk whenever the user makes changes to the menu, but this can be altered by changing the MenuAttribute's LoadOn and SaveOn properties. You can also manually load/save by calling the Load or Save methods of the ConfigFile.

Reacting to Changed Values

In some cases, merely changing the value in the ConfigFile is not enough and you will want to run some bespoke code for a specific value whenever it is changed. This is made possible by usage of the OnChangeAttribute as per the following example:

using SMLHelper.V2.Json;
using SMLHelper.V2.Options.Attributes;

[Menu("My Options Menu")]
public class MyConfig : ConfigFile
{
    /// A ToggleAttribute is used to represent a checkbox in the options menu
    /// and is backed by a bool.
    [Toggle("My checkbox"), OnChange(nameof(MyCheckboxToggleEvent))]
    public bool ToggleValue;

    /// This method will be called whenever a value with an OnChangeAttribute referencing it by name is changed.
    /// In this example, only the field ToggleValue references it, so it will only be called whenever the value of ToggleValue
    /// is changed by the user via the options menu.
    private void MyCheckboxToggleEvent(ToggleChangedEventArgs e)
    {
        Logger.Log(Logger.Level.Info, "Checkbox value was changed!");
        Logger.Log(Logger.Level.Info, $"{e.Value}");
    }
}

See MenuAttribute, ToggleAttribute and OnChangeAttribute in the attribute reference for more information on these attributes.

Attribute Reference

MenuAttribute

Namespace SMLHelper.V2.Options.Attributes
Summary Attribute used to signify an in-game options menu should be automatically generated from a ConfigFile.
Usage Decorate class inheriting from ConfigFile, register class to the OptionsPanelHandler.
Constructor public MenuAttribute(string name)
string name The display name for the generated options menu.
Properties
SaveEvents SaveOn The events after which the config file will be saved to disk automatically. Defaults to SaveEvents.ChangeValue.
LoadEvents LoadOn The events after which the config file will be loaded from disk automatically. Defaults to LoadEvents.MenuRegistered.
Members MemberProcessing How members of the ConfigFile will be processed. Defaults to Members.Explicit.

ButtonAttribute

Namespace SMLHelper.V2.Options.Attributes
Summary Attribute used to signify the decorated method should be represented in the options menu as a button. When the button is clicked, the given method will run.
Usage Decorate a public method in a ConfigFile.
Constructor public ButtonAttribute(string label = null)
string label The label for the button. If none is set, the name of the method will be used.
Constructor public ButtonAttribute()

ChoiceAttribute

Namespace SMLHelper.V2.Options.Attributes
Summary Attribute used to signify the decorated member should be represented in the options menu as a choice. Works for either int index-based, string-based, or enum-based members.
Usage Decorate a public int, string or enum field or property in a ConfigFile.
Constructor public ChoiceAttribute(string label = null, params string[] options)
string label The label for the choice. If none is set, the name of the member will be used.
params string[] options The list of options for the user to choose from.
Constructor public ChoiceAttribute(params string[] options)
params string[] options The list of options for the user to choose from.
Constructor public ChoiceAttribute()

KeybindAttribute

Namespace SMLHelper.V2.Options.Attributes
Summary Attribute used to signify the decorated KeyCode member should be represented in the options menu as a keybind.
Usage Decorate a public KeyCode field or property in a ConfigFile.
Constructor public KeybindAttribute(string label = null)
string label The label for the keybind. If none is set, the name of the member will be used.
Constructor public KeybindAttribute()

SliderAttribute

Namespace SMLHelper.V2.Options.Attributes
Summary Attribute used to signify the decorated float, double or int member should be represented in the options menu as a slider.
Usage Decorate a public float, double or int field or property in a ConfigFile.
Constructor public SliderAttribute(string label, float min, float max)
string label The label for the slider. If none is set, the name of the member will be used.
float min The minimum value of the slider.
float max The maximum value of the slider.
Constructor public SliderAttribute(float min, float max)
float min The minimum value of the slider.
float max The maximum value of the slider.
Constructor public SliderAttribute(string label = null)
string label The label for the slider. If none is set, the name of the member will be used.
Constructor public SliderAttribute()
Properties
float DefaultValue The default value of the slider - used to represent the default value as a notch on the slider in the in-game menu.
string Format The format to use when displaying the value, e.g. "{0:F2}" or "{0:F0} %".
float Step The step to apply to the slider (ie. round to nearest). For float and double, defaults to 0.05f. For int, defaults to 1. Set to 0 to indicate no stepping.

ToggleAttribute

Namespace SMLHelper.V2.Options.Attributes
Summary Attribute used to signify the decorated bool member should be represented in the options menu as a toggle (checkbox).
Usage Decorate a public bool field or property in a ConfigFile.
Constructor public ToggleAttribute(string label = null)
string label The label for the toggle. If none is set, the name of the member will be used.
Constructor public ToggleAttribute()

OnChangeAttribute

Namespace SMLHelper.V2.Options.Attributes
Summary Attribute used to signify a method to call whenever the decorated member's value changes. The method must be a member of the same ConfigFile class. Can be specified mutliple times to call multiple methods.
Usage Decorate a public field or property in a ConfigFile that represents a menu option.
Constructor public OnChangeAttribute(string methodName)
string methodName The name of the method within the same class to invoke.

OnGameObjectCreatedAttribute

Namespace SMLHelper.V2.Options.Attributes
Summary Attribute used to signify a method to call whenever the UnityEngine.GameObject for the corresponding decorated member is created. The method must be a member of the same ConfigFile class. Can be specified mutliple times to call multiple methods.
Usage Decorate a public field or property in a ConfigFile that represents a menu option.
Constructor public OnGameObjectCreatedAttribute(string methodName)
string methodName The name of the method within the same class to invoke.

IgnoreMemberAttribute

Namespace SMLHelper.V2.Options.Attributes
Summary Attribute used to signify the given property, field or method should be ignored when generating your options menu. By default, all members are ignored unless either they are decorated with a relevant attribute specifying they represent an option, or the MenuAttribute.MemberProcessing property is set to MenuAttribute.Members.Implicit.
Usage Decorate a member in a ConfigFile that you wish to specify should not be represented in the options menu.

ConfigFileAttribute

Namespace SMLHelper.V2.Json
Summary Attribute used to specify a custom filename for a ConfigFile.
Usage Decorate class inheriting from ConfigFile, register class to the OptionsPanelHandler.
Constructor public ConfigFileAttribute(string filename = "config")
string name The filename to use for the ConfigFile.
Properties
string Subfolder The subfolder within the mod's folder for the ConfigFile.

For more information on how to implement the various menu options, see the Example mod.

Using the Abstract ModOptions Class to Manually Create an In-Game Options Menu (Advanced)

For the majority of use cases, since SMLHelper 2.9 it is no longer necessary to create a class the inherits from ModOptions to create a simple options menu that saves and loads values to/from disk for use in your mod. For most use cases, it is therefore recommended to use the abstract ConfigFile class to automatically generate an in-game options menu.

If for whatever reason this use case doesn't cover your mod - e.g. you don't need a config file, or you don't want your config file to be serialized using JSON, you are targeting a version of SMLHelper older than 2.9 (why tho?) - then read on.

Inheriting from ModOptions

SMLHelper provides the ModOptions abstract class in the SMLHelper.V2.Options namespace as a base for defining your in-game options menu.

The following is a basic usage example.

using QModManager.API.ModLoading;
using SMLHelper.V2.Handlers;
using SMLHelper.V2.Options;
using Logger = QModManager.Utility.Logger;

public class Options : ModOptions
{
    public Options() : base("My Options Menu")
    {
        ToggleChanged += Options_ToggleChanged;
    }

    public override void BuildModOptions()
    {
        AddToggleOption("toggle_id", "My toggle", true);
    }

    private void Options_ToggleChanged(object sender, ToggleChangedEventArgs e)
    {
        Logger.Log(Logger.Level.Info, "checkbox was toggled!");
        Logger.Log(Logger.Level.Info, $"{e.Id}");
        
        switch (e.Id)
        {
             case "toggle_id":
                 Logger.Log(Logger.Level.Info, $"My toggle new value: {e.Value}");
                 break;
        }
    }
}

[QModCore]
public static class MyMod
{
    [QModPatch]
    public static void Patch()
    {
        OptionsPanelHandler.RegisterModOptions(new Options());
        Logger.Log(Logger.Level.Info, "Patched successfully!");
    }
}

For more details on ModOptions, check the documentation in Visual Studio.

Please note that some pages are under construction and the links to them will be enabled as they are completed

Home
Quick Start Guide

[Adding]

[Editing]

[General Utilities]

[Language]

Clone this wiki locally