-
Notifications
You must be signed in to change notification settings - Fork 37
In Game Options Menu
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.
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.
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.
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
.
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.
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 . |
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() |
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() |
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() |
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. |
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() |
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. |
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. |
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. |
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.
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.
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.
If there is something missing or ambiguous, please create an issue or contact us on the Subnautica Modding Discord using our tags:
- PrimeSonic:
@PrimeSonic#0667
- Metious:
@Metious#3682
Please note that some pages are under construction and the links to them will be enabled as they are completed
[Adding]
- Items/GameObjects using Asset Classes
- Asynchronous loading for ModPrefab
- [Custom Scanner Unlocks]
- Items/GameObjects to the Spawning System
- [Recipes to uncraftable items]
- [Custom Mouse Click Actions]
[Editing]
- Background Type
- Crafting Time
- Equipment Type
- Quick Slot Type
- Size in Inventory
- [Recipes for craftable items]
- Harvest Settings
- BioReactor Fuel Values
- [Scanning Count/Time]
- [Spawning (Where/How often/How many)]
[General Utilities]
- In-Game Options Menu
- Adding crafting recipes for other mods items
- Using items from other mods
- Texture/Sprite Utilities
- [Adding/Playing Audio]
- Config Files using Abstract Json Config class
- Custom Console Commands
- [Registering OnSave/OnQuit Actions]
[Language]