You are viewing a potentially older version of this package. View all versions.
Reverb_and___and_Spice-UIFramework-0.8.0 icon

UIFramework

A UI For settings in Rumble VR

Date uploaded 2 weeks ago
Version 0.8.0
Download link Reverb_and___and_Spice-UIFramework-0.8.0.zip
Downloads 42
Dependency string Reverb_and___and_Spice-UIFramework-0.8.0

This mod requires the following mods to function

LavaGang-MelonLoader-0.7.2 icon
LavaGang-MelonLoader

The World's First Universal Mod Loader for Unity Games compatible with both Il2Cpp and Mono

Preferred version: 0.7.2

README

btw: The changelog doubles as a feature list

New in 0.8.0

Modders read this first one

New Feature: Improved MelonPreferences_Entry.Value Behavior

The Value property for entries won't update anymore until the save button is clicked. If you need to access the new value before it's been saved, you can get the EditedValue property instead.

New Feature: Expanded Type Support

Serialization and parsing is now handled by Tomlet. Anything Tomlet supports is now technically supported by UIFramework.

More details in the Type Support section

New feature: Custom display name attribute

Just add [assembly: UIInfo("My Mod's Better\nDisplay Name")] to your assembly attributes to display your mod's name differently on its button in UI Framework. Yes, it supports line breaks

New Feature: Support IsHidden property for entries.

Entries with IsHidden set to true won't be listed in the preferences list anymore.

New Feature: New Validator Extension System.

I came up with a system to use MelonLoader's custom validator feature to add extra UI configurations for entries. The new sliders and buttons feature are implemented through this system.

New Feature: Sliders! (and maybe more eventually 👀)

Modders can now implement sliders for numeric vlaues.

MySlider = Category.CreateEntry("MySlider", 0.5f, "My Slider", "Float Slider",false, false, new SliderDescriptor { Min = 0, Max = 1, DecimalPlaces = 3 });
New Feature: Add Buttons to the Entry List

Modders can now add their own buttons as entries into UI Framework.

UI.CreateButtonEntry(MelonPreferences_Category category, string buttonText, string displayName, string description, Action handler)

Go to Buttons for more details.

Bug Fix: Fixed issue with UI Framework *displaying* ModUI's window instead of hiding

whoops

Bug Fix: Finally suppressed saved and loaded message from MelonPreferneces

I somehow missed an entire boolean. Sorry Ulvak.

*This will only affect messages when you save or load through UI Framework. It will not suppress messages from melonloader itself when the game starts or closes.


For Users

Drop the dll in your mods folder.

Default toggle is the F9 key

Changing a value of an entry automatically updates the value of the preference and is applied. How that preference's parent mod reacts depends on the modder's implementation.

* the above is no longer true as of 0.8.0. Values will not update until the saved button has been clicked

The save button writes it to the file for permanent storage. Closing your game might also save preferences to file automatically depending on whether it's closed from the game window or through Steam. Stopping through Steam doesn't save because it force closes it.


For Modders

Basic Registration

Add [assembly: MelonAdditionalDependencies("UIFramework")] to your AssemblyInfo. This prevents your mod from calling on UIFramework before it's been initialized.

Define your MelonPreferences in OnInitializeMelon and then register them to the UI.

UI.Register(this, TestCategory1, TestCategory2...);

Right now, support is limited to common types like string, int, bool, double, float, and enums without the flags attribute. Working on expanding this.

Type Support: Whatever works with Tomlet

Expanded Type Support details

Support is no longer limited to the types mentioned above. Serialization and parsing is now handled by Tomlet. This means that it supports types described in Toml 1.0.0 and whatever Tomlet supports. You can even make your own custom mappers

Caveat: Types handled by Tomlet will be presented as regular text inputs and they might not always look good. Numerics will have the appropriate filters. I do plan to continue expanding the number of custom UI presenters like I did with enums and booleans.

Optional: OnSave Event Handler

You can add an event handler that gets called when the save button is clicked while your mod is selected.

private void MyModSaved()
{
    // Do something when the save button is clicked while your mod is selected
}
UI.Register((MelonBase)this, OBSAutoRecorderSettings, TestCategory1, TestCategory2...).OnModSaved += MyModSaved;

Casting to melonbase isn't necessary but it forces your compiler to use the newer MelonBase registration instead of the obsolete MelonMod registration In the future, all mods will be registered as MelonBase by default and the cast won't be needed. But the cast makes sure that your mod won't break when the old MelonMod registration gets removed

Optional: Custom display names

Add [assembly: UIInfo("My Mod's Better\nDisplay Name")] to your assembly attributes to change how the mod's name is displayed in the UI. Line breaks are supported.


Advanced Usage

Click here for details

Interaction Type Configuration

Validator Extension system

Melonloader has a custom validator feature that you can use by inheriting the ValueValidator class. Here's an example of a custom validator that approves everything.

public class CustomValidator : ValueValidator
{
    // These two are required members
    public override bool IsValid(object value) { return true; }
    public override object EnsureValid(object value) { return value; }
}

In UI Framework, we use this system to describe how the entry is represented in the UI. This is done through implementing interfaces in the UIFramework.ValidationExtensions namespace.

UI Framework's ValidationControls namespace contains interfaces you can implement into your validator class. Each interface has required member implementations. So, if you want a slider, the declaration for your validator becomes

using UIFramework.ValidationExtensions;
public class CustomValidator : ValueValidator, SliderDescriptor
{
    // These two are required members from MelonPreferences Value Validator. 
    // You can implement actual validators here or just return true and return the same value
    public override bool IsValid(object value) { return true; }
	public override object EnsureValid(object value) { return value; }

    //You can set default values or set them when you pass a new instance into the validator parameter
    public float Min { get; set; } = 0;
    public float Max { get; set; } = 100; 
    public int DecimalPlaces { get; set; } = 5
}

Now, when you create your entry, you can pass a new instance of your validator with the appropriate properties set for the slider to be represented in the UI:

MySlider = Category.CreateEntry("MySlider", 0.5f, "My Slider", "Float Slider",false, false, new SliderDescriptor { Min = 0, Max = 1, DecimalPlaces = 3 });

Most interfaces haven't been implemented yet but I will list the available ones below as they get added

I will also have a default concrete class for most interfaces that has the required members implemented so you can just set the properties when you create a new instance of the class instead of having to make your own validator class.


Sliders

Interface: ISliderDescriptor

Default extended validator: SliderDescriptor

The UI will represent your entry with a slider if you add a validator that implements SliderDescriptor.

MySlider = Category.CreateEntry("MySlider", 0.5f, "My Slider", "Float Slider",false, false, new SliderDescriptor { Min = 0, Max = 1, DecimalPlaces = 3 });


Buttons

Interface: IButtonDescriptor

Default extended validator: ButtonAsEntry (internal)

This is a special case. You don't need to implement this yourself. Instead, you call

UI.CreateButtonEntry(MelonPreferences_Category category, string buttonText, string displayName, string description, Action handler)

This method will handle the implementation for you and it will show the button in the entries list.



If you haven't used melonpreferences before

Here's instructions for basic usage as well as a link to the official documentation for MelonPreferences from the MelonLoader wiki

1. Define a file location.

Make sure the directory exists for your mod. Otherwise, it will not fail silently and your preferences don't save at all.

private const string USER_DATA = "UserData/MyMod/";
private const string CONFIG_FILE = "config.cfg";
if (!Directory.Exists(USER_DATA))
    Directory.CreateDirectory(USER_DATA);

2. Declare MelonPreferences_Category and MelonPreferences_Entry variables

private MelonPreferences_Category TestCategory1;
private MelonPreferences_Category TestCategory2;
private MelonPreferences_Entry<string> TestEntry11;
private MelonPreferences_Entry<int> TestEntry12;

private MelonPreferences_Entry<float> TestEntry21;
private MelonPreferences_Entry<bool> TestEntry22;

3. Call the CreateCategory method and set file paths

TestCategory1 = MelonPreferences.CreateCategory("TestCat1", "Category DisplayName 1");
TestCategory1.SetFilePath(Path.Combine(USER_DATA, CONFIG_FILE));

TestCategory2 = MelonPreferences.CreateCategory("TestCat2", "Category DisplayName 2");
TestCategory2.SetFilePath(Path.Combine(USER_DATA, CONFIG_FILE));

4. Create Entries by calling the .CreateEntry method on the category they go in. Parameters are Identifier, Default Value, Display Name, and Description

TestEntry11 = TestCategory1.CreateEntry("Entry 1-1", "Test Val", "Display Name1", "Test String");
TestEntry12 = TestCategory1.CreateEntry("Entry 1-2", 1, "Display Name2", "Test Int");

TestEntry21 = TestCategory2.CreateEntry("Entry 2-1", "0.5126", "Display Name 3", "Test float");
TestEntry22 = TestCategory2.CreateEntry("Entry 2-2", true, "Display Name 4", "Test bool");

https://melonwiki.xyz/#/modders/preferences?id=melon-preferences

Events

  • MelonPreferences_Entry.OnEntryValueChanged: Event that fires when the value is changed (Value is applied when you hit the save button in the UI Framework window). Provides oldValue and newValue parameters so you can monitor if it's been changed from the previous values. Must be subscribed with via the .Subscribe() method instead of +=

Enum Display Names

Enum dropdowns will now show the Display(Name) attribute. If unavailable, it will fall back to the default enum value name.

using System.ComponentModel.DataAnnotations;
public enum Example
{
    [Display(Name = "DisplayName")]
    value1,
    [Display(Name = "Other Value")]
    value2
}

Ongoing Development Disclosure

This mod is in active development. The plan is to increase extensibility. Basic MelonPreferences registration is stable and should always be backwards compatible. So while advanced API usage will have a lot of changes for the time that this mod is in Version 0.x.x, mods that implement the basic use case of this framework don't have to worry about breaking in the future (as long as I don't mess up too bad).

Oops (0.6.2)

Well, so much for always be backwards compatible. In order to support plugins, I'm having to change .Register to use MelonBase as the instance instead of MelonMod Currently, I have an obsolete bridging function for backwards compatibility. But that will be removed in a future version if I'm confident that enough mods have migrated that it won't be too big of a problem.

In order to make your mod future proof, explicitly cast your MelonMod instance to MelonBase in your next update. You don't need to publish that update now for this small change but it makes it so that when the old function does become actually deprecated, you won't need to push an update specific to it.

UI.Register((MelonBase)this, TestCategory1, TestCategory2);

Okay, so for real this time: Basic MelonPreferences registration is stable and should always be backwards compatible.

XML Documentation File

You can place the .xml documentation file for UIFramework in the same folder as the dll to get intellisense documentation for the API. It is currently incomplete, however but I do add to it every update.

CHANGELOG

New in 0.9.0

New Feature: Reactivity Update! UI Framework can now refresh without the user having to press save or manually reloading the tab
New Feature: Update UI with current values. UI now refreshes when an entry value for a preference changes
New Feature: IsHidden support for categories UI Framework will now appropriately not show categories with the IsHidden property set to true.
New Feature: Modders can now implement an UserEditNotifier validator class. This can notify you when the user has edited their entry even when it hasn't been applied to their saved value yet.

Combined with the previous new feature, you can now adjust your UI according to your users' inputs

The following example uses it to change the visibility of certain categories based on user input without them having to hit save

//Create a method you can pass as a delegate
internal static void UpdateCategoryVis(object newValue)
{
    Experimental.IsHidden = !(bool)newValue;
    TestBooleans.IsHidden = !(bool)newValue;
    TestEmptyDisplayName.IsHidden = !(bool)newValue;
}

Create a new instance of UserEditNotifier and set this as the action for OnUserEdit

EnableDebugMode = CatUIFramework.CreateEntry("EnableDebugMode", false, "Enable Debug Logs", "Enables or disables debug logs for UIFramework.", false, false, new UserEditNotifier { OnUserEdit = UpdateCategoryVis });
New Feature: Modders can now request the window to refresh its UI.

Just call UI.RequestRefresh(modInstance)

New Feature: Dynamic dropdown support UI Framework now supports custom dropdown contents, not just from enums.

Create an items list

// It takes a list of DropdownItems which take a string as a display name, and a value of type object 
List<DropdownItem> itemList = new();

Create an instance of the DynamicDropdownDescriptor class passing the item list as a parameter in the constructor

public static DynamicDropdownDescriptor DropdownDescriptor = new(itemList);

Add items with

DropdownDescriptor.AddDropdownItem(new DropdownItem("Display Name", value)); 

or declare a list separately and set it with SetDropdownItems

Pass it into the CreateEntry validator parameter

DropdownTest = Category.CreateEntry("DropdownTest", -1, "Dropdown Test", "Dynamic dropdown test.", false, false, DropdownDescriptor);
Bug Fix: Added Flatland support UI Framework now works in Flatland

New in 0.8.2

just some backend stuff Don't worry about it

New in 0.8.1

New Feature: Draggable UI Window!

The UI window is now draggable by the title bar.

Bug Fix: Empty string display name support Buttons with empty display names will not show "Placeholder xxxx" anymore. This also applies to entries in general. Only for empty strings though. If you pass null, it will show placeholder again.
Feature change: VR toggle behavior now follows ModUI

If ModUI is enabled, and it has the VR Menu Toggle setting enabled, UI Framework will follow ModUI's visibility. If ModUI is visible (when the VR toggle is pressed), UI Framework will also be visible and vice versa. If you don't have ModUI or the setting is off, UI Framework will toggle normally with the VR toggle.

The toggle with VR buttons preference is also no longer a thing. A new preference is added for toggling with VR, keyboard, or both.

Backend enhancements just that lol

New in 0.8.0

Modders read this first one

New Feature: Improved MelonPreferences_Entry.Value Behavior

The Value property for entries won't update anymore until the save button is clicked. If you need to access the new value before it's been saved, you can get the EditedValue property instead.

New Feature: Expanded Type Support

Serialization and parsing is now handled by Tomlet. Anything Tomlet supports is now technically supported by UIFramework.

More details in the Type Support section

New feature: Custom display name attribute

Just add [assembly: UIInfo("My Mod's Better\nDisplay Name")] to your assembly attributes to display your mod's name differently on its button in UI Framework. Yes, it supports line breaks

New Feature: Support IsHidden property for entries.

Entries with IsHidden set to true won't be listed in the preferences list anymore.

New Feature: New Validator Extension System.

I came up with a system to use MelonLoader's custom validator feature to add extra UI configurations for entries. The new sliders and buttons feature are implemented through this system.

New Feature: Sliders! (and maybe more eventually 👀)

Modders can now implement sliders for numeric vlaues.

MySlider = Category.CreateEntry("MySlider", 0.5f, "My Slider", "Float Slider",false, false, new SliderDescriptor { Min = 0, Max = 1, DecimalPlaces = 3 });
New Feature: Add Buttons to the Entry List

Modders can now add their own buttons as entries into UI Framework.

UI.CreateButtonEntry(MelonPreferences_Category category, string buttonText, string displayName, string description, Action handler)

Go to Buttons for more details.

Bug Fix: Fixed issue with UI Framework *displaying* ModUI's window instead of hiding

whoops

Bug Fix: Finally suppressed saved and loaded message from MelonPreferneces

I somehow missed an entire boolean. Sorry Ulvak.

*This will only affect messages when you save or load through UI Framework. It will not suppress messages from melonloader itself when the game starts or closes.

New in 0.7.1

New setting: VR Toggle Toggle UI Framework window using your controllers by pressing both grips on both hands and pressing both primary buttons on both hands (X and A)
New setting: Force Hide ModUI Never leave ModUI accidentally open again. Enabling this setting will make UI Framework hide the ModUI window when UI Framework hides. This setting does not support the inactivity timer if ModUI is open by itself but does support hide on scene load
Bug fix: (hopefully) Fix layout quirks involving scroll views Hopefully, this fixes the issue with tabs all being squished to one side or only half showing.

New in 0.6.2

New Feature: Plugin support I just completely forgot about those.

I did have to change the .Register() function's signature. Right now, I have an overload for the old function for backwards compatibility. More details at the bottom of the page

New Feature: Exposed UI.IsVisible Property Your mod can now check if UIFramework is currently open.

Version 0.6.1

New Feature: Exposed OnModSaved event for modders

You can now subscribe to the OnModSaved event that triggers when the saved button is clicked while your mod is selected. This is an alternative for OnPreferencesSaved from MelonPreferences which gets called per category. This one is called once and only if your mod is selected.

UI.Register(this, OBSAutoRecorderSettings, TestCategory1, TestCategory2...).OnModSaved += MyModSaved;
Bug Fix: Increased Supported Mod Name Length Longer mod names can now fit into the mod list

*btw while text wrapping is disabled in mod list buttons, your MelonInfo name property does support spaces and line breaks that you can add manually if your mod name is still too long to fit into one line

Bug Fix: Fixed bug that called the selected category save action twice

Version 0.6.0

New Feature: Hide UI on inactivity Added settings to hide the UI after a certain amount of inactivity with keyboard and mouse.

Comes with new settings:

  • Auto Hide on Inactivity
  • Inactivity Timeout
New Feature: Remembers last category opened for each mod Moving between mods will now show the last category you were on for that mod. Will default to the first category. No more having to select the same category again when switching between mods.
New Feature: Selection highlighting Selected mods and categories will now be colored in the UI.

Version 0.5.1

New Feature: Non-contiguous enum support You can now use enum types that are non-sequential and non-zero-based for your dropdowns
New Feature: Discard button

Made discard button visible to load the saved values from the preferences file

Version 0.5.0

  • Added support for enum display names
  • Save button now saves the entire mod, not just the selected tab

Version 0.4.0

  • Created