Plugin Tutorial: Managing Settings
Most plugins will need to save and load settings. Melon provides
IStorageAPI
for this purpose. It allows you to define an
object as your settings class and save/load it in one line, along with
built in security with encrypted fields. This saves the object to the
Melon/Configs folder as <name>.json
.
Step-by-Step Guide
1. Create a Configuration Class
Define a class to hold your plugin's settings. This can support any values json supports.
public class MyPluginConfig
{
public string GreetingMessage { get; set; }
public bool EnableFeatureX { get; set; }
}
2. Load and Save Settings Using IStorageAPI
a. Load Settings
public MyPluginConfig Config { get; set; }
private void LoadConfig()
{
Config = Host.Storage.LoadConfigFile<MyPluginConfig>("MyPluginConfig", null, out bool converted);
if (Config == null)
{
Config = new MyPluginConfig
{
GreetingMessage = "Hello from My First Plugin!",
EnableFeatureX = true
};
Host.Storage.SaveConfigFile("MyPluginConfig", Config, null);
}
}
b. Save Settings
private void SaveConfig()
{
Host.Storage.SaveConfigFile("MyPluginConfig", Config, null);
}
3. Use Settings in Your Plugin
Modify your plugin main menu code to use the greeting setting.
private void MyPluginMenu()
{
while (true)
{
Host.MelonUI.BreadCrumbBar(new List<string> { "Melon", "My First Plugin" });
var choice = Host.MelonUI.OptionPicker(new List<string>
{
"Back",
"Greet",
"Show Date",
"Perform Calculation"
});
switch (choice)
{
case "Back":
return;
case "Greet":
// Use the new config set greeting
Console.WriteLine(Config.GreetingMessage);
break;
case "Show Date":
Console.WriteLine($"Today's date is {DateTime.Now.ToShortDateString()}");
break;
case "Perform Calculation":
PerformCalculation();
break;
}
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}
}
4. Create a Settings Menu
Allow users to modify settings.
private void SettingsMenu()
{
while (true)
{
Host.MelonUI.BreadCrumbBar(new List<string> { "Melon", "My First Plugin Settings" });
var choice = Host.MelonUI.OptionPicker(new List<string>
{
"Back",
"Change Greeting Message",
Config.EnableFeatureX ? "Disable Feature X" : "Enable Feature X"
});
switch (choice)
{
case "Back":
return;
case "Change Greeting Message":
Console.Write("Enter new greeting message: ");
var input = Console.ReadLine();
if (!string.IsNullOrWhiteSpace(input))
{
Config.GreetingMessage = input;
SaveConfig();
}
break;
case "Disable Feature X":
case "Enable Feature X":
Config.EnableFeatureX = !Config.EnableFeatureX;
SaveConfig();
break;
}
}
}
5. Update LoadUI Method to Include Settings Menu
public int LoadUI()
{
Host.DisplayManager.MenuOptions.Add("My First Plugin", MyPluginMenu);
Host.SettingsUI.MenuOptions.Add("My First Plugin Settings", SettingsMenu); // Add new Settings Menu Option to the SettinsUI.MenuOptions
return 0;
}
6. Initialize Config
Ensure you load the config when the plugin is initialized. Plugins get initialized twice, once for UI and once for Server processes, but you'll want to load your config both times.
public void LoadMelonCommands(IHost host)
{
Host = host;
LoadConfig();
}
public void LoadMelonServerCommands(IWebApi webapi)
{
WebApi = webapi;
LoadConfig();
}
7. Watching for changes
When you update the config file through the console, or with a text editor, the server wont have a way to know the config has changed unless you tell it.
watcher = new FileSystemWatcher();
watcher.Path = $"{Host.StateManager.melonPath}/Configs/";
watcher.NotifyFilter = NotifyFilters.LastWrite
| NotifyFilters.FileName
| NotifyFilters.DirectoryName;
watcher.Filter = "*.json";
FileSystemEventHandler func = (sender, args) =>
{
if(args.Name == "MyPluginConfig.json")
{
// Check if settings have actually changed
var temp = Storage.LoadConfigFile<Settings>("MelonSettings", null, out _);
if (StateManager.MelonSettings == null || temp == null ||
Storage.PropertiesEqual(StateManager.MelonSettings, temp))
{
return;
}
StateManager.MelonSettings = temp;
}
};
// Add event handlers.
watcher.Changed += func;
watcher.Created += func;
watcher.EnableRaisingEvents = true;
Make sure to make the watcher variable global, if it is disposed it will stop watching.
8. Rebuild and Test
- Rebuild your plugin.
- Copy the DLL to Melon's
Plugins
directory. - Restart Melon.
- Navigate to "My First Plugin Settings" to modify settings.
- Verify changes take effect in your plugin.
Last Tutorial: First UI <--- ---> Next Tutorial: Custom Endpoints