The_AsheR-Nivalis_Mod_Settings icon

Nivalis Mod Settings

A Mods tab in the game's own Settings window, plus a Mods menu button. Any BepInEx plugin can list its settings there with one API call.

Last updated 2 hours ago
Total downloads 5
Total rating 0 
Categories Mods AI Generated
Dependency string The_AsheR-Nivalis_Mod_Settings-1.0.1
Dependants 0 other packages depend on this package

This mod requires the following mods to function

BepInEx-BepInExPack_IL2CPP-6.0.788 icon
BepInEx-BepInExPack_IL2CPP

BepInEx pack for IL2CPP x64 Unity games. Preconfigured and ready to use.

Preferred version: 6.0.788

README

Nivalis Settings

A Nivalis Nights mod (BepInEx 6 IL2CPP). It adds a Mods tab to the game's Settings window, and a Mods button to the main and pause menus that opens Settings straight on that tab.

Any BepInEx plugin can list its ConfigFile settings in that tab with a single API call. The rows look like the game's own: sliders, toggles and left/right choices.

For players

  1. Install with r2modman or Gale, or manually drop NivalisSettings.dll into BepInEx/plugins (requires BepInExPack IL2CPP).
  2. In game, open Settings → Mods, or press the Mods button in the menu.

Mods that support it: Nivalis Jump, Nivalis Bhop, Nivalis Parkour. Other plugins can be shown too with ShowAllPlugins (see below).

How the tab works:

  • Changes apply immediately. They are written to the .cfg files when you leave the tab or close the window.
  • Restore defaults resets every setting shown in the tab to its default value.
  • To rebind a key setting, click its row and press the new key. Esc cancels.

The mod's own settings (BepInEx/config/com.asher.nivalissettings.cfg):

Setting Default What it does
Menu.MenuButton true Mods button in the main and pause menus
Menu.ShowAllPlugins false Also list plugins that don't use the API, showing every entry of their config
Debug.DumpUi false Write the Settings window hierarchy to the log, for debugging

For mod authors

1. Reference the assembly

Reference the DLL from your .csproj without copying it into your build output: at runtime it is a separate plugin.

<ItemGroup>
  <Reference Include="path/to/NivalisSettings.dll" Private="false" />
</ItemGroup>

Mod managers install it to BepInEx/plugins/The_AsheR-Nivalis_Mod_Settings/NivalisSettings.dll. On Thunderstore, add The_AsheR-Nivalis_Mod_Settings-1.0.1 to your dependencies only if your mod requires it (a soft dependency needs nothing there).

2. Register your settings

The simplest setup, where your mod requires NivalisSettings:

using NivalisSettings;

[BepInPlugin("com.me.mymod", "My Mod", "1.0.0")]
[BepInDependency(ModSettings.Guid)]
public class Plugin : BasePlugin
{
    public override void Load()
    {
        var speed = Config.Bind("Movement", "Speed", 5f,
            new ConfigDescription("Speed, m/s", new AcceptableValueRange<float>(1f, 20f)));
        var enabled = Config.Bind("General", "Enabled", true, "Turn the mod on/off");

        ModSettings.Register(this);   // every entry of Config shows up in the Mods tab
    }
}

3. Recommended: soft dependency

With a soft dependency your mod still works without NivalisSettings; it just has no menu. Keep every NivalisSettings type inside a separate method marked NoInlining. .NET then loads the assembly only when that method actually runs.

using System.Runtime.CompilerServices;
using BepInEx.Unity.IL2CPP;

[BepInPlugin("com.me.mymod", "My Mod", "1.0.0")]
[BepInDependency(NivalisSettings.ModSettings.Guid, BepInDependency.DependencyFlags.SoftDependency)]
public class Plugin : BasePlugin
{
    public override void Load()
    {
        // ... Config.Bind(...) ...
        if (IL2CPPChainloader.Instance.Plugins.ContainsKey(NivalisSettings.ModSettings.Guid))
            RegisterSettings();
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    private void RegisterSettings()
    {
        NivalisSettings.ModSettings.Register(this);
    }
}

ModSettings.Guid is a constant that the compiler copies into your assembly, so [BepInDependency] and ContainsKey work even when the mod isn't installed. SoftDependency makes sure NivalisSettings loads before your plugin when it is installed.

4. Customize the page

Register returns a ModPage. Its methods return the same page, so you can chain the calls.

NivalisSettings.ModSettings.Register(this, "My Mod")  // custom name instead of the [BepInPlugin] name
    .Label(speed, "Run speed")                 // label instead of the key "Speed"
    .SectionLabel("Movement", "Movement")      // section title
    .Hide(internalCounter)                     // don't show this entry
    .HideSection("Debug")                      // don't show a whole section
    .Button("Tools", "Reset stats", () => Stats.Reset())
    .Order = 10;                               // position in the list, lower = higher up

API reference

ModSettings (static class)

Member Description
const string Guid The plugin GUID, "com.asher.nivalissettings"
ModPage Register(BasePlugin plugin, string displayName = null) Registers plugin.Config. The name defaults to the one in [BepInPlugin]. Calling it again returns the same page.
ModPage Register(string id, string displayName, ConfigFile config) Registers any ConfigFile under a unique id, for example a mod's second config file.
void Unregister(string id) Removes a page. For a plugin, id is its GUID.
IReadOnlyList<ModPage> RegisteredPages All registered pages

ModPage

Member Description
string Id, ConfigFile Config Read-only
string DisplayName Title of the mod's block in the tab
int Order Block order: by Order first, then by name
Hide(ConfigEntryBase entry) Hide an entry
HideSection(string section) Hide every entry of a section
Label(ConfigEntryBase entry, string label) Entry label. Defaults to the key with spaces added: BufferTime → Buffer Time.
SectionLabel(string section, string label) Section title
Button(string section, string label, Action onClick) A clickable row that calls onClick. The section is created if it doesn't exist.

You can change a page after registering it, for example to show or hide an entry. An open tab rebuilds itself.

How entry types are shown

Entry type Control
bool Toggle
int, float, double Slider. Bounds come from AcceptableValueRange<T>; without one, it goes from 0 to 4× the default value.
enum Left/right choice over all enum values
any type with AcceptableValueList<T> Left/right choice over the listed values
string whose key ends in Key, or whose value is a UnityEngine.InputSystem.Key name Key rebind: click, then press a key
anything else Value shown read-only

Tips:

  • Give numbers an AcceptableValueRange. Without one the slider bounds are guessed, and guessed badly.
  • Slider precision depends on the range. Values round to 0.001 for ranges up to 2, 0.01 up to 20, 0.1 up to 200, and whole numbers beyond that.
  • Hide debug switches from players. Use .HideSection("Debug"); they stay in the .cfg for bug reports.
  • Write a Description anyway. It stays in the .cfg for people who edit the file by hand.
  • Read entry.Value every time you need the value. Then changes made in the menu take effect in game immediately. If you cache it, subscribe to entry.SettingChanged.

Order within a block

Sections appear in the order of your Config.Bind calls, and the Debug section always comes last. If a mod has a single section, its title isn't shown. Rows added with Button(...) go at the end of their section.

About

I wanted to tweak my mods right from the game instead of digging through .cfg files.

I made these mods with Claude (AI). Claude wrote the code; I came up with the ideas, played it over and over, broke things, and kept sending it back until it felt right. Have fun!