• Hi Guest!

    We are extremely excited to announce the release of our first Beta for VaM2, the next generation of Virt-A-Mate which is currently in development.
    To participate in the Beta, a subscription to the Entertainer or Creator Tier is required. Once subscribed, download instructions can be found here.

    Click here for information and guides regarding the VaM2 beta. Join our Discord server for more announcements and community discussion about VaM2.
PluginReloader

Plugins + Scripts PluginReloader

Download [0.01 MB]
Are you sure it is reloading "as well" or is it the only one reloading? My observation was that only one plugin is reloaded, the top one.
I'm not sure. I was looking at the expression randomizer to reload because when the model changed, I had to manually reload it to get the expressions working again. With v2 I was seeing the expressions start working again.
 
V2 does reload the correct plugin, even it it is not the top one. That's good, I do not know of the other disadvantages of the method used in V2 though.

EDIT: Ah, I see, its not a full "fake" reload button onclick invoke order, but an atom.RestoreFromLast(plugin) function. In my specific case, for the Stopper AltFuta plugin when switching skin beforehand, this reload method does not work, but it might in many other cases.
 
Last edited:
This is the code block I use to fake a Reload button click to achieve a full plugin reload (the same as if you click on Reload in the UI of the plugin).

The code still contains full debug info, which can be removed.

C#:
protected void removePlugin(string selectedPlugin, string function)
{
    //This function serves to either remove or reload a certain plugin. The string selectedPlugin should contain the plugin creator and plugin name (e.g. RunRudolf.ControlCenter), the string function can be either "Reload" or "Remove".
    SuperController.LogError("2. " + function + selectedPlugin + " plugin");
    Atom atom = containingAtom;
    if (atom == null) return;

    var pluginManager = atom.GetStorableByID("PluginManager") as MVRPluginManager;
    if (pluginManager == null) return;

    Transform panelRoot = pluginManager.UITransform;
    if (panelRoot == null) return;

    foreach (Transform pluginPanel in panelRoot)
    {
        Text[] allTexts = pluginPanel.GetComponentsInChildren<Text>(true);
        Button[] buttons = pluginPanel.GetComponentsInChildren<Button>(true);

        //1. Count the number of plugin#? text entries (e.g. "plugin#1")
        List<Text> pluginTexts = new List<Text>();
        Regex pattern1 = new Regex(@"^plugin#\d+$");
        foreach (var txt in allTexts)
        {
            if (!string.IsNullOrEmpty(txt.text) && pattern1.IsMatch(txt.text))
            {
                pluginTexts.Add(txt);
            }
        }
        SuperController.LogError(function + ": " + pluginTexts.Count + " plugin#? gefunden.");
        //DEBUG
        StringBuilder sb = new StringBuilder();
        foreach (Text tx in pluginTexts)
        {
            sb.AppendLine(tx.text);
        }
        string result1 = sb.ToString();
        SuperController.LogError(result1);

        //2. Count the number of plugin#?_? text entries (e.g. "plugin#1_RunRudolf.ControlCenter")
        List<Text> pluginTexts2 = new List<Text>();
        Regex pattern2 = new Regex(@"^plugin#\d+_.+$");
        foreach (var txt in allTexts)
        {
            if (!string.IsNullOrEmpty(txt.text) && pattern2.IsMatch(txt.text))
            {
                pluginTexts2.Add(txt);
            }
        }
        SuperController.LogError(function + ": " + pluginTexts2.Count + " plugin#?_? gefunden.");
        //DEBUG
        StringBuilder sb2 = new StringBuilder();
        foreach (Text tx in pluginTexts2)
        {
            sb2.AppendLine(tx.text);
        }
        string result2 = sb2.ToString();
        SuperController.LogError(result2);

        //3. Determine position of selectedPlugin
        string escapedPlugin = Regex.Escape(selectedPlugin);
        Regex pattern3 = new Regex($@"^plugin#\d+_{escapedPlugin}$");
        for (int i = 0; i < pluginTexts2.Count; i++)
        {
            if (pattern3.IsMatch(pluginTexts2[i].text))
            {
                int position1 = i + 1;
                SuperController.LogError(function + ": " + "'" + selectedPlugin + "' gefunden an Position " + position1 + " von " + pluginTexts2.Count);

                //4. Determine plugin#? at position i+1 (index i)
                string text = pluginTexts2[i].text;
                SuperController.LogError(function + ": " + text);

                if (text.Contains("_"))
                {
                    string[] parts = text.Split('_');
                    if (parts.Length > 1)
                    {
                        string pluginId = parts[0];
                        SuperController.LogError(function + ": " + "PluginID von " + selectedPlugin + ": " + pluginId);

                        //5. Compare selectedPlugin to plugin#? from list in 1
                        int index = pluginTexts.FindIndex(t => t.text == pluginId);
                        if (index >= 0)
                        {
                            int position2 = index + 1;
                            SuperController.LogError(function + ": " + pluginId + " gefunden an Position: " + position2);

                            //6. Count number of Reload/Remove buttons
                            List<Button> reloadButtons = new List<Button>();
                            foreach (var btn in buttons)
                            {
                                string btnText = btn.GetComponentInChildren<Text>()?.text;
                                if (btnText == function)
                                {
                                    reloadButtons.Add(btn);
                                }
                            }
                            SuperController.LogError(function + ": " + reloadButtons.Count + " " + function + " Buttons gefunden.");

                            //7. Execute Button at correct position
                            //Reload buttons for plugins are positioned in the UI starting from index 0, Remove buttons for plugins start at index 1 (first is atom remove)
                            if (function == "Reload")
                            {
                                position2 = position2 - 1;
                            }
                            reloadButtons[position2].onClick.Invoke();
                            SuperController.LogError(function + ": " + function + " Button for " + selectedPlugin + " clicked at index: " + position2);
                            return;
                        }
                    }
                }
            }
        }
    }
}

You can call this function by either using
removePlugin("Stopper.AlternativeFuta", "Reload"); or removePlugin("Stopper.AlternativeFuta", "Remove");

Replace the text "Stopper.AlternativeFuta" with your plugin URL, e.g. RunRudolf.ControlCenter. You can also use a variable there of course.

And attached you find the hierarchy of the VaM plugin UI, in order to understand why I did all this. You can search there for "plugin#", "Reload" or "Remove" to find the relevant entries.
 

Attachments

  • DumpHierarchyPluginPanel.txt
    1,013.1 KB · Views: 0
Last edited:
This is the code block I use to fake a Reload button click to achieve a full plugin reload (the same as if you click on Reload in the UI of the plugin).

The code still contains full debug info, which can be removed.

C#:
protected void removePlugin(string selectedPlugin, string function)
{
    //This function serves to either remove or reload a certain plugin. The string selectedPlugin should contain the plugin creator and plugin name (e.g. RunRudolf.ControlCenter), the string function can be either "Reload" or "Remove".
    SuperController.LogError("2. " + function + selectedPlugin + " plugin");
    Atom atom = containingAtom;
    if (atom == null) return;

    var pluginManager = atom.GetStorableByID("PluginManager") as MVRPluginManager;
    if (pluginManager == null) return;

    Transform panelRoot = pluginManager.UITransform;
    if (panelRoot == null) return;

    foreach (Transform pluginPanel in panelRoot)
    {
        Text[] allTexts = pluginPanel.GetComponentsInChildren<Text>(true);
        Button[] buttons = pluginPanel.GetComponentsInChildren<Button>(true);

        //1. Count the number of plugin#? text entries (e.g. "plugin#1")
        List<Text> pluginTexts = new List<Text>();
        Regex pattern1 = new Regex(@"^plugin#\d+$");
        foreach (var txt in allTexts)
        {
            if (!string.IsNullOrEmpty(txt.text) && pattern1.IsMatch(txt.text))
            {
                pluginTexts.Add(txt);
            }
        }
        SuperController.LogError(function + ": " + pluginTexts.Count + " plugin#? gefunden.");
        //DEBUG
        StringBuilder sb = new StringBuilder();
        foreach (Text tx in pluginTexts)
        {
            sb.AppendLine(tx.text);
        }
        string result1 = sb.ToString();
        SuperController.LogError(result1);

        //2. Count the number of plugin#?_? text entries (e.g. "plugin#1_RunRudolf.ControlCenter")
        List<Text> pluginTexts2 = new List<Text>();
        Regex pattern2 = new Regex(@"^plugin#\d+_.+$");
        foreach (var txt in allTexts)
        {
            if (!string.IsNullOrEmpty(txt.text) && pattern2.IsMatch(txt.text))
            {
                pluginTexts2.Add(txt);
            }
        }
        SuperController.LogError(function + ": " + pluginTexts2.Count + " plugin#?_? gefunden.");
        //DEBUG
        StringBuilder sb2 = new StringBuilder();
        foreach (Text tx in pluginTexts2)
        {
            sb2.AppendLine(tx.text);
        }
        string result2 = sb2.ToString();
        SuperController.LogError(result2);

        //3. Determine position of selectedPlugin
        string escapedPlugin = Regex.Escape(selectedPlugin);
        Regex pattern3 = new Regex($@"^plugin#\d+_{escapedPlugin}$");
        for (int i = 0; i < pluginTexts2.Count; i++)
        {
            if (pattern3.IsMatch(pluginTexts2[i].text))
            {
                int position1 = i + 1;
                SuperController.LogError(function + ": " + "'" + selectedPlugin + "' gefunden an Position " + position1 + " von " + pluginTexts2.Count);

                //4. Determine plugin#? at position i+1 (index i)
                string text = pluginTexts2[i].text;
                SuperController.LogError(function + ": " + text);

                if (text.Contains("_"))
                {
                    string[] parts = text.Split('_');
                    if (parts.Length > 1)
                    {
                        string pluginId = parts[0];
                        SuperController.LogError(function + ": " + "PluginID von " + selectedPlugin + ": " + pluginId);

                        //5. Compare selectedPlugin to plugin#? from list in 1
                        int index = pluginTexts.FindIndex(t => t.text == pluginId);
                        if (index >= 0)
                        {
                            int position2 = index + 1;
                            SuperController.LogError(function + ": " + pluginId + " gefunden an Position: " + position2);

                            //6. Count number of Reload/Remove buttons
                            List<Button> reloadButtons = new List<Button>();
                            foreach (var btn in buttons)
                            {
                                string btnText = btn.GetComponentInChildren<Text>()?.text;
                                if (btnText == function)
                                {
                                    reloadButtons.Add(btn);
                                }
                            }
                            SuperController.LogError(function + ": " + reloadButtons.Count + " " + function + " Buttons gefunden.");

                            //7. Execute Button at correct position
                            //Reload buttons for plugins are positioned in the UI starting from index 0, Remove buttons for plugins start at index 1 (first is atom remove)
                            if (function == "Reload")
                            {
                                position2 = position2 - 1;
                            }
                            reloadButtons[position2].onClick.Invoke();
                            SuperController.LogError(function + ": " + function + " Button for " + selectedPlugin + " clicked at index: " + position2);
                            return;
                        }
                    }
                }
            }
        }
    }
}

You can call this function by either using
removePlugin("Stopper.AlternativeFuta", "Reload"); or removePlugin("Stopper.AlternativeFuta", "Remove");

Replace the text "Stopper.AlternativeFuta" with your plugin URL, e.g. RunRudolf.ControlCenter. You can also use a variable there of course.

And attached you find the hierarchy of the VaM plugin UI, in order to understand why I did all this. You can search there for "plugin#", "Reload" or "Remove" to find the relevant entries.
I'm just a simple cave man and I don't understand your "modern inventions". But, I do know this looks crazy enough that is just might work!
 
This is the code block I use to fake a Reload button click to achieve a full plugin reload (the same as if you click on Reload in the UI of the plugin).

The code still contains full debug info, which can be removed.

C#:
protected void removePlugin(string selectedPlugin, string function)
{
    //This function serves to either remove or reload a certain plugin. The string selectedPlugin should contain the plugin creator and plugin name (e.g. RunRudolf.ControlCenter), the string function can be either "Reload" or "Remove".
    SuperController.LogError("2. " + function + selectedPlugin + " plugin");
    Atom atom = containingAtom;
    if (atom == null) return;

    var pluginManager = atom.GetStorableByID("PluginManager") as MVRPluginManager;
    if (pluginManager == null) return;

    Transform panelRoot = pluginManager.UITransform;
    if (panelRoot == null) return;

    foreach (Transform pluginPanel in panelRoot)
    {
        Text[] allTexts = pluginPanel.GetComponentsInChildren<Text>(true);
        Button[] buttons = pluginPanel.GetComponentsInChildren<Button>(true);

        //1. Count the number of plugin#? text entries (e.g. "plugin#1")
        List<Text> pluginTexts = new List<Text>();
        Regex pattern1 = new Regex(@"^plugin#\d+$");
        foreach (var txt in allTexts)
        {
            if (!string.IsNullOrEmpty(txt.text) && pattern1.IsMatch(txt.text))
            {
                pluginTexts.Add(txt);
            }
        }
        SuperController.LogError(function + ": " + pluginTexts.Count + " plugin#? gefunden.");
        //DEBUG
        StringBuilder sb = new StringBuilder();
        foreach (Text tx in pluginTexts)
        {
            sb.AppendLine(tx.text);
        }
        string result1 = sb.ToString();
        SuperController.LogError(result1);

        //2. Count the number of plugin#?_? text entries (e.g. "plugin#1_RunRudolf.ControlCenter")
        List<Text> pluginTexts2 = new List<Text>();
        Regex pattern2 = new Regex(@"^plugin#\d+_.+$");
        foreach (var txt in allTexts)
        {
            if (!string.IsNullOrEmpty(txt.text) && pattern2.IsMatch(txt.text))
            {
                pluginTexts2.Add(txt);
            }
        }
        SuperController.LogError(function + ": " + pluginTexts2.Count + " plugin#?_? gefunden.");
        //DEBUG
        StringBuilder sb2 = new StringBuilder();
        foreach (Text tx in pluginTexts2)
        {
            sb2.AppendLine(tx.text);
        }
        string result2 = sb2.ToString();
        SuperController.LogError(result2);

        //3. Determine position of selectedPlugin
        string escapedPlugin = Regex.Escape(selectedPlugin);
        Regex pattern3 = new Regex($@"^plugin#\d+_{escapedPlugin}$");
        for (int i = 0; i < pluginTexts2.Count; i++)
        {
            if (pattern3.IsMatch(pluginTexts2[i].text))
            {
                int position1 = i + 1;
                SuperController.LogError(function + ": " + "'" + selectedPlugin + "' gefunden an Position " + position1 + " von " + pluginTexts2.Count);

                //4. Determine plugin#? at position i+1 (index i)
                string text = pluginTexts2[i].text;
                SuperController.LogError(function + ": " + text);

                if (text.Contains("_"))
                {
                    string[] parts = text.Split('_');
                    if (parts.Length > 1)
                    {
                        string pluginId = parts[0];
                        SuperController.LogError(function + ": " + "PluginID von " + selectedPlugin + ": " + pluginId);

                        //5. Compare selectedPlugin to plugin#? from list in 1
                        int index = pluginTexts.FindIndex(t => t.text == pluginId);
                        if (index >= 0)
                        {
                            int position2 = index + 1;
                            SuperController.LogError(function + ": " + pluginId + " gefunden an Position: " + position2);

                            //6. Count number of Reload/Remove buttons
                            List<Button> reloadButtons = new List<Button>();
                            foreach (var btn in buttons)
                            {
                                string btnText = btn.GetComponentInChildren<Text>()?.text;
                                if (btnText == function)
                                {
                                    reloadButtons.Add(btn);
                                }
                            }
                            SuperController.LogError(function + ": " + reloadButtons.Count + " " + function + " Buttons gefunden.");

                            //7. Execute Button at correct position
                            //Reload buttons for plugins are positioned in the UI starting from index 0, Remove buttons for plugins start at index 1 (first is atom remove)
                            if (function == "Reload")
                            {
                                position2 = position2 - 1;
                            }
                            reloadButtons[position2].onClick.Invoke();
                            SuperController.LogError(function + ": " + function + " Button for " + selectedPlugin + " clicked at index: " + position2);
                            return;
                        }
                    }
                }
            }
        }
    }
}

You can call this function by either using
removePlugin("Stopper.AlternativeFuta", "Reload"); or removePlugin("Stopper.AlternativeFuta", "Remove");

Replace the text "Stopper.AlternativeFuta" with your plugin URL, e.g. RunRudolf.ControlCenter. You can also use a variable there of course.

And attached you find the hierarchy of the VaM plugin UI, in order to understand why I did all this. You can search there for "plugin#", "Reload" or "Remove" to find the relevant entries.


I added the code block you provided that uses regex to find plugins and got it to load. I added the plugin on an empty atom pointed to a person and click reload on plugins and it does not work when I tested it. Can you show the full working version so can compare. Do you want me to update it on this plugin, or if you want you can upload your own version if you prefer.
 

Attachments

  • PluginReloader.cs
    17.4 KB · Views: 0
I added the code block you provided that uses regex to find plugins and got it to load. I added the plugin on an empty atom pointed to a person and click reload on plugins and it does not work when I tested it. Can you show the full working version so can compare. Do you want me to update it on this plugin, or if you want you can upload your own version if you prefer.
I use it in my plugins, but you can use it too in your plugin if you want. It works well in the version I posted - only thing I could imagine is that you are missing one of the following tools. I dont know however which ones are needed for this specific part of the code, so you maybe try with all of them and then reduce if you want.

C#:
using System;

using System.Text;

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UnityEngine.UI;

using UnityEngine.Events;

using System.Linq;

using SimpleJSON;

using AssetBundles;

using System.Text.RegularExpressions;

using MeshVR;

using MVR.Hub;

using MVR.FileManagementSecure;

This is again the code (this time with debug info not showing:
C#:
protected void removePlugin(string selectedPlugin, string function)
{
    //This function serves to either remove or reload a certain plugin. The string selectedPlugin should contain the plugin creator and plugin name (e.g. RunRudolf.ControlCenter), the string function can be either "Reload" or "Remove".
    //SuperController.LogError("2. " + function + selectedPlugin + " plugin"); //DEBUGG
    Atom atom = containingAtom;
    if (atom == null) return;

    var pluginManager = atom.GetStorableByID("PluginManager") as MVRPluginManager;
    if (pluginManager == null) return;

    Transform panelRoot = pluginManager.UITransform;
    if (panelRoot == null) return;

    foreach (Transform pluginPanel in panelRoot)
    {
        Text[] allTexts = pluginPanel.GetComponentsInChildren<Text>(true);
        Button[] buttons = pluginPanel.GetComponentsInChildren<Button>(true);

        //1. Count the number of plugin#? text entries (e.g. "plugin#1")
        List<Text> pluginTexts = new List<Text>();
        Regex pattern1 = new Regex(@"^plugin#\d+$");
        foreach (var txt in allTexts)
        {
            if (!string.IsNullOrEmpty(txt.text) && pattern1.IsMatch(txt.text))
            {
                pluginTexts.Add(txt);
            }
        }
        //SuperController.LogError(function + ": " + pluginTexts.Count + " plugin#? gefunden."); //DEBUGG
        //DEBUGG
        //StringBuilder sb = new StringBuilder();
        //foreach (Text tx in pluginTexts)
        //{
        //    sb.AppendLine(tx.text);
        //}
        //string result1 = sb.ToString();
        //SuperController.LogError(result1); //DEBUGG

        //2. Count the number of plugin#?_? text entries (e.g. "plugin#1_RunRudolf.ControlCenter")
        List<Text> pluginTexts2 = new List<Text>();
        Regex pattern2 = new Regex(@"^plugin#\d+_.+$");
        foreach (var txt in allTexts) 
        {
            if (!string.IsNullOrEmpty(txt.text) && pattern2.IsMatch(txt.text))
            {
                pluginTexts2.Add(txt);
            }
        }
        //SuperController.LogError(function + ": " + pluginTexts2.Count + " plugin#?_? gefunden."); //DEBUGG
        //DEBUGG
        //StringBuilder sb2 = new StringBuilder();
        //foreach (Text tx in pluginTexts2)
        //{
        //    sb2.AppendLine(tx.text);
        //}
        //string result2 = sb2.ToString();
        //SuperController.LogError(result2); //DEBUGG

        //3. Determine position of selectedPlugin
        string escapedPlugin = Regex.Escape(selectedPlugin);
        Regex pattern3 = new Regex($@"^plugin#\d+_{escapedPlugin}$");
        for (int i = 0; i < pluginTexts2.Count; i++)
        { 
            if (pattern3.IsMatch(pluginTexts2[i].text))
            {
                int position1 = i + 1;
                //SuperController.LogError(function + ": " + "'" + selectedPlugin + "' gefunden an Position " + position1 + " von " + pluginTexts2.Count); //DEBUGG

                //4. Determine plugin#? at position i+1 (index i)
                string text = pluginTexts2[i].text;
                //SuperController.LogError(function + ": " + text); //DEBUGG

                if (text.Contains("_"))
                {
                    string[] parts = text.Split('_');
                    if (parts.Length > 1)
                    {
                        string pluginId = parts[0];
                        //SuperController.LogError(function + ": " + "PluginID von " + selectedPlugin + ": " + pluginId); //DEBUGG

                        //5. Compare selectedPlugin to plugin#? from list in 1
                        int index = pluginTexts.FindIndex(t => t.text == pluginId);
                        if (index >= 0)
                        {
                            int position2 = index + 1;
                            //SuperController.LogError(function + ": " + pluginId + " gefunden an Position: " + position2); //DEBUGG

                            //6. Count number of Reload/Remove buttons
                            List<Button> reloadButtons = new List<Button>();
                            foreach (var btn in buttons)
                            {
                                string btnText = btn.GetComponentInChildren<Text>()?.text;
                                if (btnText == function)
                                {
                                    reloadButtons.Add(btn);
                                }
                            }
                            //SuperController.LogError(function + ": " + reloadButtons.Count + " " + function + " Buttons gefunden."); //DEBUGG

                            //7. Execute Button at correct position
                            //Reload buttons for plugins are positioned in the UI starting from index 0, Remove buttons for plugins start at index 1 (first is atom remove)
                            if (function == "Reload")
                            {
                                position2 = position2 - 1;
                            }
                            reloadButtons[position2].onClick.Invoke();
                            //SuperController.LogError(function + ": " + function + " Button for " + selectedPlugin + " clicked at index: " + position2); //DEBUGG
                            return;
                        }
                    }
                }
            }
        }
    }
}

You can call this with
C#:
removePlugin("Stopper.AlternativeFuta", "Remove"); or removePlugin("Stopper.AlternativeFuta", "Reload");
I dont think it uses any other defined variables or stuff from the Init().

What errors do you get?
 
I use it in my plugins, but you can use it too in your plugin if you want. It works well in the version I posted - only thing I could imagine is that you are missing one of the following tools. I dont know however which ones are needed for this specific part of the code, so you maybe try with all of them and then reduce if you want.

C#:
using System;

using System.Text;

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UnityEngine.UI;

using UnityEngine.Events;

using System.Linq;

using SimpleJSON;

using AssetBundles;

using System.Text.RegularExpressions;

using MeshVR;

using MVR.Hub;

using MVR.FileManagementSecure;

This is again the code (this time with debug info not showing:
C#:
protected void removePlugin(string selectedPlugin, string function)
{
    //This function serves to either remove or reload a certain plugin. The string selectedPlugin should contain the plugin creator and plugin name (e.g. RunRudolf.ControlCenter), the string function can be either "Reload" or "Remove".
    //SuperController.LogError("2. " + function + selectedPlugin + " plugin"); //DEBUGG
    Atom atom = containingAtom;
    if (atom == null) return;

    var pluginManager = atom.GetStorableByID("PluginManager") as MVRPluginManager;
    if (pluginManager == null) return;

    Transform panelRoot = pluginManager.UITransform;
    if (panelRoot == null) return;

    foreach (Transform pluginPanel in panelRoot)
    {
        Text[] allTexts = pluginPanel.GetComponentsInChildren<Text>(true);
        Button[] buttons = pluginPanel.GetComponentsInChildren<Button>(true);

        //1. Count the number of plugin#? text entries (e.g. "plugin#1")
        List<Text> pluginTexts = new List<Text>();
        Regex pattern1 = new Regex(@"^plugin#\d+$");
        foreach (var txt in allTexts)
        {
            if (!string.IsNullOrEmpty(txt.text) && pattern1.IsMatch(txt.text))
            {
                pluginTexts.Add(txt);
            }
        }
        //SuperController.LogError(function + ": " + pluginTexts.Count + " plugin#? gefunden."); //DEBUGG
        //DEBUGG
        //StringBuilder sb = new StringBuilder();
        //foreach (Text tx in pluginTexts)
        //{
        //    sb.AppendLine(tx.text);
        //}
        //string result1 = sb.ToString();
        //SuperController.LogError(result1); //DEBUGG

        //2. Count the number of plugin#?_? text entries (e.g. "plugin#1_RunRudolf.ControlCenter")
        List<Text> pluginTexts2 = new List<Text>();
        Regex pattern2 = new Regex(@"^plugin#\d+_.+$");
        foreach (var txt in allTexts)
        {
            if (!string.IsNullOrEmpty(txt.text) && pattern2.IsMatch(txt.text))
            {
                pluginTexts2.Add(txt);
            }
        }
        //SuperController.LogError(function + ": " + pluginTexts2.Count + " plugin#?_? gefunden."); //DEBUGG
        //DEBUGG
        //StringBuilder sb2 = new StringBuilder();
        //foreach (Text tx in pluginTexts2)
        //{
        //    sb2.AppendLine(tx.text);
        //}
        //string result2 = sb2.ToString();
        //SuperController.LogError(result2); //DEBUGG

        //3. Determine position of selectedPlugin
        string escapedPlugin = Regex.Escape(selectedPlugin);
        Regex pattern3 = new Regex($@"^plugin#\d+_{escapedPlugin}$");
        for (int i = 0; i < pluginTexts2.Count; i++)
        {
            if (pattern3.IsMatch(pluginTexts2[i].text))
            {
                int position1 = i + 1;
                //SuperController.LogError(function + ": " + "'" + selectedPlugin + "' gefunden an Position " + position1 + " von " + pluginTexts2.Count); //DEBUGG

                //4. Determine plugin#? at position i+1 (index i)
                string text = pluginTexts2[i].text;
                //SuperController.LogError(function + ": " + text); //DEBUGG

                if (text.Contains("_"))
                {
                    string[] parts = text.Split('_');
                    if (parts.Length > 1)
                    {
                        string pluginId = parts[0];
                        //SuperController.LogError(function + ": " + "PluginID von " + selectedPlugin + ": " + pluginId); //DEBUGG

                        //5. Compare selectedPlugin to plugin#? from list in 1
                        int index = pluginTexts.FindIndex(t => t.text == pluginId);
                        if (index >= 0)
                        {
                            int position2 = index + 1;
                            //SuperController.LogError(function + ": " + pluginId + " gefunden an Position: " + position2); //DEBUGG

                            //6. Count number of Reload/Remove buttons
                            List<Button> reloadButtons = new List<Button>();
                            foreach (var btn in buttons)
                            {
                                string btnText = btn.GetComponentInChildren<Text>()?.text;
                                if (btnText == function)
                                {
                                    reloadButtons.Add(btn);
                                }
                            }
                            //SuperController.LogError(function + ": " + reloadButtons.Count + " " + function + " Buttons gefunden."); //DEBUGG

                            //7. Execute Button at correct position
                            //Reload buttons for plugins are positioned in the UI starting from index 0, Remove buttons for plugins start at index 1 (first is atom remove)
                            if (function == "Reload")
                            {
                                position2 = position2 - 1;
                            }
                            reloadButtons[position2].onClick.Invoke();
                            //SuperController.LogError(function + ": " + function + " Button for " + selectedPlugin + " clicked at index: " + position2); //DEBUGG
                            return;
                        }
                    }
                }
            }
        }
    }
}

You can call this with
C#:
removePlugin("Stopper.AlternativeFuta", "Remove"); or removePlugin("Stopper.AlternativeFuta", "Reload");
I dont think it uses any other defined variables or stuff from the Init().

What errors do you get?


Ok I thought you said you modified this plugin and got it to work to reload other plugins using regex. When I tried the method it did not work for this plugin. Maybe it will work in individual plugins but I wasn't able to get it to work with this example of reloading other plugins.

I attached the full script if you want to replace it with existing and test it. It does not reload other plugins unfortunately.

I got it to load though so it has the required using's at the top to get it to load with no errors and it's recognizing the method. Just when you load it on an empty atom and select a person and plugin it does not reload it.
 
Ok I thought you said you modified this plugin and got it to work to reload other plugins using regex. When I tried the method it did not work for this plugin. Maybe it will work in individual plugins but I wasn't able to get it to work with this example of reloading other plugins.

I attached the full script if you want to replace it with existing and test it. It does not reload other plugins unfortunately.

I got it to load though so it has the required using's at the top to get it to load with no errors and it's recognizing the method. Just when you load it on an empty atom and select a person and plugin it does not reload it.
just to be clear: This is not for use in session plugins! Did you adapt the containingAtom stuff?
You can now see what it does in my plugins, I published V69 of RunRudolf.RealisticForeskin&Erection. It is in the ControlCenter .cs.
 
This is the code block I use to fake a Reload button click to achieve a full plugin reload (the same as if you click on Reload in the UI of the plugin).

The code still contains full debug info, which can be removed.

C#:
protected void removePlugin(string selectedPlugin, string function)
{
    //This function serves to either remove or reload a certain plugin. The string selectedPlugin should contain the plugin creator and plugin name (e.g. RunRudolf.ControlCenter), the string function can be either "Reload" or "Remove".
    SuperController.LogError("2. " + function + selectedPlugin + " plugin");
    Atom atom = containingAtom;
    if (atom == null) return;

    var pluginManager = atom.GetStorableByID("PluginManager") as MVRPluginManager;
    if (pluginManager == null) return;

    Transform panelRoot = pluginManager.UITransform;
    if (panelRoot == null) return;

    foreach (Transform pluginPanel in panelRoot)
    {
        Text[] allTexts = pluginPanel.GetComponentsInChildren<Text>(true);
        Button[] buttons = pluginPanel.GetComponentsInChildren<Button>(true);

        //1. Count the number of plugin#? text entries (e.g. "plugin#1")
        List<Text> pluginTexts = new List<Text>();
        Regex pattern1 = new Regex(@"^plugin#\d+$");
        foreach (var txt in allTexts)
        {
            if (!string.IsNullOrEmpty(txt.text) && pattern1.IsMatch(txt.text))
            {
                pluginTexts.Add(txt);
            }
        }
        SuperController.LogError(function + ": " + pluginTexts.Count + " plugin#? gefunden.");
        //DEBUG
        StringBuilder sb = new StringBuilder();
        foreach (Text tx in pluginTexts)
        {
            sb.AppendLine(tx.text);
        }
        string result1 = sb.ToString();
        SuperController.LogError(result1);

        //2. Count the number of plugin#?_? text entries (e.g. "plugin#1_RunRudolf.ControlCenter")
        List<Text> pluginTexts2 = new List<Text>();
        Regex pattern2 = new Regex(@"^plugin#\d+_.+$");
        foreach (var txt in allTexts)
        {
            if (!string.IsNullOrEmpty(txt.text) && pattern2.IsMatch(txt.text))
            {
                pluginTexts2.Add(txt);
            }
        }
        SuperController.LogError(function + ": " + pluginTexts2.Count + " plugin#?_? gefunden.");
        //DEBUG
        StringBuilder sb2 = new StringBuilder();
        foreach (Text tx in pluginTexts2)
        {
            sb2.AppendLine(tx.text);
        }
        string result2 = sb2.ToString();
        SuperController.LogError(result2);

        //3. Determine position of selectedPlugin
        string escapedPlugin = Regex.Escape(selectedPlugin);
        Regex pattern3 = new Regex($@"^plugin#\d+_{escapedPlugin}$");
        for (int i = 0; i < pluginTexts2.Count; i++)
        {
            if (pattern3.IsMatch(pluginTexts2[i].text))
            {
                int position1 = i + 1;
                SuperController.LogError(function + ": " + "'" + selectedPlugin + "' gefunden an Position " + position1 + " von " + pluginTexts2.Count);

                //4. Determine plugin#? at position i+1 (index i)
                string text = pluginTexts2[i].text;
                SuperController.LogError(function + ": " + text);

                if (text.Contains("_"))
                {
                    string[] parts = text.Split('_');
                    if (parts.Length > 1)
                    {
                        string pluginId = parts[0];
                        SuperController.LogError(function + ": " + "PluginID von " + selectedPlugin + ": " + pluginId);

                        //5. Compare selectedPlugin to plugin#? from list in 1
                        int index = pluginTexts.FindIndex(t => t.text == pluginId);
                        if (index >= 0)
                        {
                            int position2 = index + 1;
                            SuperController.LogError(function + ": " + pluginId + " gefunden an Position: " + position2);

                            //6. Count number of Reload/Remove buttons
                            List<Button> reloadButtons = new List<Button>();
                            foreach (var btn in buttons)
                            {
                                string btnText = btn.GetComponentInChildren<Text>()?.text;
                                if (btnText == function)
                                {
                                    reloadButtons.Add(btn);
                                }
                            }
                            SuperController.LogError(function + ": " + reloadButtons.Count + " " + function + " Buttons gefunden.");

                            //7. Execute Button at correct position
                            //Reload buttons for plugins are positioned in the UI starting from index 0, Remove buttons for plugins start at index 1 (first is atom remove)
                            if (function == "Reload")
                            {
                                position2 = position2 - 1;
                            }
                            reloadButtons[position2].onClick.Invoke();
                            SuperController.LogError(function + ": " + function + " Button for " + selectedPlugin + " clicked at index: " + position2);
                            return;
                        }
                    }
                }
            }
        }
    }
}

You can call this function by either using
removePlugin("Stopper.AlternativeFuta", "Reload"); or removePlugin("Stopper.AlternativeFuta", "Remove");

Replace the text "Stopper.AlternativeFuta" with your plugin URL, e.g. RunRudolf.ControlCenter. You can also use a variable there of course.

And attached you find the hierarchy of the VaM plugin UI, in order to understand why I did all this. You can search there for "plugin#", "Reload" or "Remove" to find the relevant entries.
It does not work because all plugin entries are found twice:

1748374995192.png


I expect this happens because your plugin stores the plugin names for the selector list. This could happen with other plugins too, so it might be a general problem.
I will try to find a way to identify and exclude these.
 
It does not work because all plugin entries are found twice:

View attachment 492427

I expect this happens because your plugin stores the plugin names for the selector list. This could happen with other plugins too, so it might be a general problem.
I will try to find a way to identify and exclude these.
Try this. This works for me, I had to add a few additional code lines and fix the issue with the double text fields (consider only UID entries).

BTW, you have been forwarding the string format "plugin#0_Runrudolf.ControlCenter" instead of just "RunRudolf.ControlCenter" with selectedPlugin, which led to another error (silent though). I adapted the routine with another Regex match to forward the string as needed.

Note that this method does not depend on the plugin in any way, it really fakes a click on "Reload" in the UI, which will reload each and every plugin. But it will not restore any plugin / preset data.
 

Attachments

  • PluginReloader.cs
    19.1 KB · Views: 0
Try this. This works for me, I had to add a few additional code lines and fix the issue with the double text fields (consider only UID entries).

BTW, you have been forwarding the string format "plugin#0_Runrudolf.ControlCenter" instead of just "RunRudolf.ControlCenter" with selectedPlugin, which led to another error (silent though). I adapted the routine with another Regex match to forward the string as needed.

Note that this method does not depend on the plugin in any way, it really fakes a click on "Reload" in the UI, which will reload each and every plugin. But it will not restore any plugin / preset data.

Thank you! I haven't had a chance to look at the code yet, will look at it this weekend.
 
Try this. This works for me, I had to add a few additional code lines and fix the issue with the double text fields (consider only UID entries).

BTW, you have been forwarding the string format "plugin#0_Runrudolf.ControlCenter" instead of just "RunRudolf.ControlCenter" with selectedPlugin, which led to another error (silent though). I adapted the routine with another Regex match to forward the string as needed.

Note that this method does not depend on the plugin in any way, it really fakes a click on "Reload" in the UI, which will reload each and every plugin. But it will not restore any plugin / preset data.
I just tested this version, added on an empty atom pointed to a person, and it reloads the first plugin on person but not the 2nd. I put ExpressionRouter on as the 2nd plugin, loaded some morphs and turned it on active just to confirm. I reload on 2nd and it does not reload it/clear plugin morphs/stop active for example. I use that plugin to confirm if it's working along with AwasAutoJuice on 1st as someone mentioned that as an issue previously. So I click some buttons on that to turn on juice and it reloads it on 1st. But on 2nd it's not working still.

I think this PluginReloader is just too problematic, maybe I need to remove it from the hub as it seems to be very limited in what is possible. V2 will reload some, V3 will reload more but only first, and this version seems to have same issue as v3. So there doesn't seem to be a good reliable version I can release.
 
I just tested this version, added on an empty atom pointed to a person, and it reloads the first plugin on person but not the 2nd. I put ExpressionRouter on as the 2nd plugin, loaded some morphs and turned it on active just to confirm. I reload on 2nd and it does not reload it/clear plugin morphs/stop active for example. I use that plugin to confirm if it's working along with AwasAutoJuice on 1st as someone mentioned that as an issue previously. So I click some buttons on that to turn on juice and it reloads it on 1st. But on 2nd it's not working still.

I think this PluginReloader is just too problematic, maybe I need to remove it from the hub as it seems to be very limited in what is possible. V2 will reload some, V3 will reload more but only first, and this version seems to have same issue as v3. So there doesn't seem to be a good reliable version I can release.
Please send a short video of your testing procedure where unintended behaviour occurs. I dont get everything from your description.

I think it is very well possible to do as we do it, maybe we need to account for more cases though.
 
This is the test scene I use. I have the plugin connected locally in scripts folder with that version you gave with regex resetting it. It resets 1st but second does not on the person. 2nd is ExpressionRouter with Orgasm Morphs loaded into it.

Can be anything like SilverExpression with morphs, whatever morph tool you prefer. I used ExpressionRouter so can see something actually on and working. It does not reload it/clear it. So I see same issue.

PluginReloader is on the PluginReloader atom, an Empty Atom. Script is in Custom/Scripts/VamEssentials/PluginReloader and just manually replaced with the file you gave for testing.

Testing is with 2 plugins on the person atom. First reloads, 2nd does not.
 

Attachments

  • PluginReloaderTest.json
    139.6 KB · Views: 0
This is the test scene I use. I have the plugin connected locally in scripts folder with that version you gave with regex resetting it. It resets 1st but second does not on the person. 2nd is ExpressionRouter with Orgasm Morphs loaded into it.

Can be anything like SilverExpression with morphs, whatever morph tool you prefer. I used ExpressionRouter so can see something actually on and working. It does not reload it/clear it. So I see same issue.

PluginReloader is on the PluginReloader atom, an Empty Atom. Script is in Custom/Scripts/VamEssentials/PluginReloader and just manually replaced with the file you gave for testing.

Testing is with 2 plugins on the person atom. First reloads, 2nd does not.
Funny thing here. It works as it should, reloading either plugin#0 or plugin#1. See this video:



Don't get disturbed by the plugin name of AutoJuice which stays. You can check whether it has been reloaded by changing any setting in AutoJuice and then reload it via your plugin. It will be reset to defaults after reloading.

The funny thing here is that AutoJuice seems to restore the plugin name also, which is very unusual. I expect that it has a custom restore override function. That's no problem though, the plugin is properly reloaded.
 
Back
Top Bottom