Every plugin has its own compilation context, it does not know the code of other plugins.
However, there are a number of methods for plugins to communicate:
Putting multiple MVRScript into a single plugin
You can use a *.cslist to just add multiple MVRScript. They will all be in the same compilation context and talk to each other. This makes sense for modular plugins like Life and PostMagic. Its also the most efficient method, if everything can indeed live on the same atom. Once the scripts found each other and have cached a reference, there is no performance downside anymore. Initialization order is defined by order in the *.cslist. You can use this helper method from MacGruber Utils (CC-BY):
C#:
// VaM Plugins can contain multiple Scripts, if you load them via a *.cslist file. This function allows you to get
// an instance of another script within the same plugin, allowing you directly interact with it by reading/writing
// data, calling functions, etc.
public static T FindWithinSamePlugin<T>(MVRScript self) where T : MVRScript
{
int i = self.name.IndexOf('_');
if (i < 0)
return null;
string prefix = self.name.Substring(0, i+1);
string scriptName = prefix + typeof(T).FullName;
return self.containingAtom.GetStorableByID(scriptName) as T;
}
Using MVRScript + JSONStorable
You still know any other plugin will be an MVRScript. That means you can still access JSONStorable's for example. So, all you need is find a place for your global plugin so other plugins can easily connect to it. That could be under Scene plugins or searching for an Empty atom in the scene with a particular unique name.
JSONStorable's have callbacks you can register to, so the target plugin can know when something changed.
Using Unity's SendMessage
Every MonoBehaviour in Unity engine has a SendMessage method. Therefore MVRScript has it, too. This allows you to call methods with void return value and zero or one parameter value just by giving the method name as a string. Because this is using Reflection (a C# feature), this is fairly slow. It should only be used for rare calls, e.g. to allow plugins to find each other and then storing references. Definitely not for regular calls every frame.
Another helper method from MacGruber Utils (CC-BY) that tries to call a method on ALL plugins on ALL atoms in the scene. If you need an example, this is used for FocusAreas in my Connect plugin.
C#:
// Send message to all plugins on atoms in the scene. This includes the 'Scene Plugins' tab, but doens't include 'Session Plugins'.
// Different VaM Plugins don't know of each other or their datatypes. However, using this you can call public methods with no or
// only a single parameter. As parameter types you can only use standard C#/Unity/VaM types, but not your own definitions.
// It's recommended to use long/explicit method names. For example you could include your creator name and the name of the plugin.
// This helps avoid conflicts between different plugins. Performance isn't too good, so it should only be used for occasional calls.
//
// Example:
// public void MacGruber_VirtualLock_RegisterFocusArea(MVRScript focusAreaScript) { /*...*/ }
//
// Which can then be called like this:
// Utils.SendMessageToPluginsInScene("MacGruber_VirtualLock_RegisterFocusArea", this);
public static void SendMessageToPluginsInScene(string method, object parameter)
{
List<Atom> atoms = SuperController.singleton.GetAtoms();
for (int i=0; i<atoms.Count; ++i)
{
Atom atom = atoms[i];
List<string> storables = atom.GetStorableIDs();
for (int j=0; j<storables.Count; ++j)
{
MVRScript plugin = atom.GetStorableByID(storables[j]) as MVRScript;
if (plugin != null)
plugin.SendMessage(method, parameter, SendMessageOptions.DontRequireReceiver);
}
}
}