MacGruber Utils

MacGruber Utils is a C# script containing many helper functions that simplify creating UI elements and custom triggers inside Virt‑a‑Mate (VaM). Instead of writing the same boilerplate code to create toggles, sliders, text fields, or triggers, you can call these ready‑made methods, which do all the heavy lifting for you.

Main Benefits

Functions like SetupToggle(), SetupSliderFloat(), or SetupTextInput() let you quickly add user interface elements (toggles, sliders, text fields) without manually setting up their positions, anchors, and references every time.

Because these helpers instantiate existing VaM prefabs (like scrollable popups, text fields, color pickers), your UI elements will match the standard VaM style.

The script also includes classes like SimpleTriggerHandler, CustomTrigger, EventTrigger, and FloatTrigger. These let you create your own triggers (e.g., to turn lights on/off or hide atoms) that integrate with VaM’s trigger panels. You can open a panel to manage these triggers, set up actions, and call them with one button.

By having a single “MacGruber_Utils.cs” file, you keep your main plugin scripts lean and readable. You simply call these utilities whenever you need a new UI element or custom trigger.

Key Sections & Functions

UI Creation Functions

SetupToggle(MVRScript script, string label, bool defaultValue, bool rightSide) Creates a toggle (checkbox) in VaM’s UI. Returns a JSONStorableBool that you can read or write in your code.

SetupSliderFloat(MVRScript script, string label, float defaultValue, float minValue, float maxValue, bool rightSide) Creates a slider in the VaM UI. You get back a JSONStorableFloat you can use to store or retrieve the slider’s current value.

SetupTextInput(MVRScript script, string label, JSONStorableString storable, bool rightSide) Creates a text field with a label in VaM. The user can type text, which is stored in your JSONStorableString.

SetupButton(MVRScript script, string label, UnityAction callback, bool rightSide) Creates a clickable button in VaM. When pressed, it calls your callback function.

… and more (like SetupColor, SetupInfoText, SetupStringChooser), each designed to simplify a specific type of UI element.

Custom Trigger System

SimpleTriggerHandler Loads the asset bundles containing VaM’s built‐in trigger panel UI, so you can display your custom triggers in the same style as VaM’s native triggers.

CustomTrigger (abstract class) The base class for your own triggers. It inherits from VaM’s built-in Trigger class. It has methods like OpenPanel()which displays the trigger’s UI panel, and an abstract InitPanel() that you override to customize your panel’s layout.

EventTrigger and FloatTrigger Two ready‐made subclasses of CustomTrigger.

  • EventTrigger is used to fire discrete actions (like turning something on/off).
  • FloatTrigger is for continuous (float) values (like gradually changing something over time).

You can also create your own subclass if you need specialized logic.

Utilities for Removing or Destroying UI Elements

RemoveUIElements(MVRScript script, List menuElements) A handy function to remove a bunch of UI elements at once (e.g., toggles, sliders, text fields) when you need to rebuild or refresh your plugin’s UI.

Miscellaneous Helpers

GetPluginPath(MVRScript self) and GetPackagePath(MVRScript self) Help you figure out where your plugin files are stored on disk or in a package.

LogTransform(…) A debug function that prints detailed info about a transform hierarchy (e.g., for troubleshooting your UI layout).

QueueLoadTexture(…) An internal helper used for loading textures asynchronously via ImageLoaderThreaded.

How Do I Use It?

  1. Include the Script: Make sure the “MacGruber_Utils.cs” script is in your VaM Custom/Scripts/… folder (or within your .var package). It must compile alongside your main plugin script.
  2. Use a .cslist File: Since “MacGruber_Utils.cs” is a separate file, you must compile both files together using a .cslist. For example, create a .cslist file (e.g., MyPlugin.cslist) with the following contents:
src/MacGruber_Utils.cs
src/MyScript.cs

This ensures that VaM compiles both scripts as a single plugin.

  1. Import the Namespace: At the top of your plugin script, add:
using MacGruber; // or the namespace from the Utils script

so you can call its functions directly.

  1. Call Utility Functions in Init(): In your plugin’s Init() method (which runs when the plugin loads), call the utility methods to build your UI. Important: Before calling any MacGruber UI methods (such as SetupTextInput), you must load the required assets and initialize the UI container. Do this by calling:
SimpleTriggerHandler.LoadAssets();
Utils.OnInitUI(CreateUIElement);

These calls ensure that all required UI prefabs (including those used for text input) are loaded and available. Without these calls, functions like SetupTextInput may return null and cause runtime errors. For example:

public override void Init()
{
    // Load MacGruber assets and initialize the UI container.
    SimpleTriggerHandler.LoadAssets();
    Utils.OnInitUI(CreateUIElement);
    
    // Create a toggle:
    JSONStorableBool myToggle = Utils.SetupToggle(this, "My Toggle", true, false);
    
    // Create a slider:
    JSONStorableFloat mySlider = Utils.SetupSliderFloat(this, "My Slider", 0.5f, 0f, 1f, false);
    
    // Create a button:
    Utils.SetupButton(this, "Do Something", () =>
    {
        SuperController.LogMessage("Button clicked!");
    }, false);
    
    // Create an editable text input field:
    JSONStorableString myInput = new JSONStorableString("My Input", "", (string newVal) => { /* callback */ });
    RegisterString(myInput);
    UIDynamicLabelInput inputField = Utils.SetupTextInput(this, "My Input", myInput, false);
    // Now you have an actual input field that can be typed into.
}
  1. Call the Functions in Init(): In your plugin’s Init() method (which runs when the plugin loads), call the utility methods to build your UI. For example:
public override void Init()
{
    // Create a toggle
    JSONStorableBool myToggle = Utils.SetupToggle(this, "My Toggle", true, false);
    
    // Create a slider
    JSONStorableFloat mySlider = Utils.SetupSliderFloat(this, "My Slider", 0.5f, 0f, 1f, false);

    // Create a button
    Utils.SetupButton(this, "Do Something", () =>
    {
        SuperController.LogMessage("Button clicked!");
    }, false);
}
  1. (Optional) Use Custom Triggers:
  • If you want your own triggers, either subclass CustomTrigger or use the built‐in EventTrigger or FloatTrigger.
  • Call SimpleTriggerHandler.LoadAssets() early on to ensure the trigger panel UI is available.
  • Create your trigger instance, then call myTrigger.OpenPanel() to display it.

Example of Custom Event Trigger Integration

This sample plugin demonstrates how to use the MacGruber Utils and custom trigger system in Virt‑a‑Mate. It creates a single custom trigger (an EventTrigger) and binds two JSONStorableActions to UI buttons. One button opens the trigger panel (displaying the custom trigger’s UI), and the other button fires the trigger’s action. Log messages are printed to the VaM console to indicate when actions

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using System.Collections.Generic;
// Import the MacGruber namespace which contains the custom trigger utilities and helper classes.
using MacGruber;

public class TestTriggerPlugin : MVRScript
{
    // Single instance of our custom trigger.
    private EventTrigger trigger;

    public override void Init()
    {
        // Load the trigger UI assets if they haven't been loaded already.
        SimpleTriggerHandler.LoadAssets();

        // Create a new EventTrigger.
        // The first parameter ("Test Trigger") sets the primary name that appears on the panel header.
        // The second parameter ("Secondary Info") sets the secondary text that appears alongside it.
        trigger = new EventTrigger(this, "Test Trigger", "Secondary Info");

        // Create a JSONStorableAction that opens the trigger panel when invoked.
        JSONStorableAction openPanelAction = new JSONStorableAction("OpenPanel", () =>
        {
            trigger.OpenPanel();
            SuperController.LogMessage("OpenPanel() called on Test Trigger.");
        });
        RegisterAction(openPanelAction);

        // Create a button in the VaM UI and bind it to the openPanelAction.
        // Clicking this button will open the trigger panel (using our custom trigger).
        UIDynamicButton openPanelButton = CreateButton("Open Trigger Panel", false);
        openPanelButton.button.onClick.AddListener(() =>
        {
            openPanelAction.actionCallback.Invoke();
        });

        // Create a JSONStorableAction that triggers the custom trigger.
        // Since we only have one trigger, this action simply fires that one trigger.
        JSONStorableAction triggerAllAction = new JSONStorableAction("TriggerAll", () =>
        {
            trigger.Trigger();
            SuperController.LogMessage("Triggered: " + trigger.Name);
        });
        RegisterAction(triggerAllAction);

        // Create another button in the UI and bind it to the triggerAllAction.
        // Clicking this button will execute the trigger's action.
        UIDynamicButton triggerAllButton = CreateButton("Trigger All Triggers", false);
        triggerAllButton.button.onClick.AddListener(() =>
        {
            triggerAllAction.actionCallback.Invoke();
        });

        SuperController.LogMessage("TestTriggerPlugin initialized. Use the buttons to open the trigger panel and trigger the trigger.");
    }
}

Prev