• Hello Guest!

    We have recently updated our Site Policies regarding the use of Non Commercial content within Paid Content posts. Please read the new policy here.

    An offical announcement about this new policy can be read on our Discord.

    ~The VaMHub Moderation Team
  • Hello Guest!

    We posted an announcment regarding upcoming changes to Paid Content submissions.

    Please see this thread for more information.

Hello World - plugin basics

Guides Hello World - plugin basics 1

Hi Gang,

I haven't seen loads of documentation on getting started with plug-in development so, as a beginner, I wrote one.
The target audience is those who, like me, have made some attempt at VaM plugins and/or scripting in Unity. Hopefully, you have Unity installed (the correct version for VaM) and a code editor of sorts.

ThaHellHounds Learning VaM Programming guide pulled together some C# and Unity resources. A good place to start.

First a few nuggets of knowledge

There are 3 types of plugins.

Scene plugins scope of the plugin is this scene when it is loaded
Session plugins scope is this session, for all scenes until you close VaM
Atom plugins do something with an atom - including 'people'.

Plugins are simply *.cs script files (Mono C# - Microsofts open source variation of .Net framework)

They derive from (or extend - or inherit from) VaMs MVRScript which itself is a subclass of Unity's MonoBehaviour.

In other words, you can use all the 'stuff' (methods/properties) that are hidden away in VaMs MVRScript (the so-called superclass of your script).

MVRScript can use all the stuff hidden away in Unity's MonoBehaviour Class which in turn will inherit all sorts of 'stuff' from its superclass.

Side note: here are the official docs for MonoBehaviour. At the top of the page, you will find the class it inherits from and can follow the trail all the way to the base class - 'Object'.

Some of the stuff hidden in the superclass hierarchy is available (Public) to you - to use in your script. Some of it is kept 'Private' only to be used within the containing script/class file.

Side note: Public/Private/Protected are known as Access Modifiers and control how objects, functions, properties are exposed and accessible - now, you can google the differences.

Some plugins need settings (dials and knobs to tweak). Some do not.
If you need input from the user, you will need to build the dials and knobs - User Interface (UI - sometimes referred to as UX for User Experience Design).

A Basic Implementation...

To write your plugin script, I'd recommend using Microsoft VS Code at bare minimum.

You might not be aware but a better experience is to use the 'Plugin Builder' tool included in the VaM release. It's a Microsoft Visual Studio Solution and so, requires an installation of Visual Studio.

I found more intellisense help using the Builder and Studio than from VS Code. Here's an example of the difference:
VSStudio VS VSCode 1.JPG
<--Studio Versus VSCode-->​
VSStudio VS VSCode 2.JPG

For those using Studio;
  • The solution uses .NET framework v4.6.1 which I downloaded when prompted (the developer pack) rather than change the solution to point to whatever newer version I already had installed. I'm not sure if this step was necessary but seemed the safest.
  • Within the VaM root folder, find plugin builder at Custom\Scripts\MeshedVR\PluginBuilder.sln
  • On opening the solution, if the 'Object Browser' pane is not visible, click View > Object Browser. Then pin it open.
  • Right-click PluginBuilder in the 'Search Solution Explorer' pane. Choose: Add > New Item > Class (C#)

For those using VS Code or similar, start with a template file such as this basic example. (see download button at the top) .

It's a good idea to wrap your code in try/catch blocks so you may handle errors gracefully and not affecting VaM stability.
A bare bones template including try/catches blocks and helpful comments is included by Mesh @ Custom\Scripts\MeshedVR\Template.cs

Change the namespace in the script to something you will use throughout all your plugins

Make sure your class inherits from MVRScript (gives you access to 'stuff' such as JSONStorable properties)
NameSpaceClass Inherits.jpg


Add some comments about the author (you) and date and version - and what does this plugin do

This minimal plugin contains a button that increments a counter and a slider.

C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//using System.Threading.Tasks; // VaM throws an error when this is left included. Not needed?

namespace NoButYeaNS
{
    class NBYPluginTest01: MVRScript
    {
        protected JSONStorableFloat jsonFloat;
        protected UIDynamicButton myButton;
  
        protected Int16 counterValue; // store the value of our counter
        protected Boolean counterValueIsValid; // set to false upon making a change. So we can recoginse a change was made in Update()

        protected float sliderValue; // tracks the slider value (frame to frame)


        public override void Init()
        {
            pluginLabelJSON.val = "NoButYea Test 1.0";


            // CreateSlider needs a JSONStorableFloat value so..
            // Initialize storable values.
            jsonFloat = new JSONStorableFloat("jsonFloat", 0.0f, 0.0f, 1.0f);
            RegisterFloat(jsonFloat); // Registering the float is important -- if not they wont save
            CreateSlider(jsonFloat, true); // the second argument is for 'rightSide'. Supplying true will render the slider on the right-side

            // track the value of the slider so that...
            // we can track if a change was made since last frame.
            sliderValue = jsonFloat.val; // initialize to whatever the slider is now.
      
            // Initialize the counter (that the button will influence)
            counterValue = 0;
            counterValueIsValid = false;
      
            // Add a button and a click handler
            myButton = CreateButton("My Button", false);
            myButton.height = 100;
            myButton.button.onClick.AddListener(delegate ()
            {
                // increase counter value
                counterValue++;
                counterValueIsValid = false; // so we can detect a change was made

            });
      
        }
  

        // Runs once when plugin loads - after Init()
        protected void Start()
        {
            // show a message
            SuperController.LogMessage(pluginLabelJSON.val + " Loaded");
        }

        // A Unity thing - runs every physics cycle
        public void FixedUpdate()
        {
            // put code here
        }

        // Unity thing - runs every rendered frame
        public void Update()
        {
      
            if(counterValueIsValid == false) // check if counter has changed since last frame
            {
                SuperController.LogMessage("counter change detected: " + counterValue);
                counterValueIsValid = true; // set to true to avoid log message every frame
            }

            if(jsonFloat.val != sliderValue) // check if slider was changed since last frame
            {
                sliderValue = jsonFloat.val; // update our tracking value
                SuperController.LogMessage("slider value change detected: " + sliderValue);
            }



        }


    }
}

Overview of the methods in the class...
Init - set the default values for properties we have defined
Start - just print a message to say the plugin is loaded
FixedUpdate - nothing yet
Update - each frame, check for changes and print a message when something changes (rather than continuous messages - every frame)

Side note: to know what 'type' you should use when creating a variable that references a UI component (such as a Slider or Button); Start typing the word 'Create' and observe the return type from intellisense.
Create_IntelliSense 2.JPG


Once the script is saved, drop the .cs file somewhere in Custom\Scripts\
e.g.
<VaM root>\Custom\Scripts\YouAuthorName\YourClass.cs

Open VaM, load a scene, find the plugins window, (either scene plugin, session plugin or select an atom).
Click to add Plugin and choose your .cs file from the file explorer.

Click 'Open Custom UI...' to see the Button and Slider.

You should see changes to the counter variable or slider outputted in a message box.

If your plugin is RED and you see an error log - check the imports at the top of your script file against mine.

Also, be sure to check the .cs files from other author plugins (just unpack the var with 7-zip) for example code and inspiration.

For my first non-test plugin, I'll be attempting to do something with VR controller positional metrics. If that works out ill reference to it here.

Update: click here for part 2 - November 2021:


Hope this helps someone - DM me with any inaccuracies because ill edit the guide.
Any questions or problems with the plugin/script or loading, comment here for other user benefit - they might have the same issues.

Regards
Author
nobutyea
Downloads
729
Views
14,476
First release
Last update
Rating
4.50 star(s) 4 ratings

More resources from nobutyea

Latest reviews

Thank you for this guide!
Upvote 0
Thanks for doing this. I'm starting to get the idea of how plugins are created. Actually not as bad as I'd feared, but without a guide like this hand holding through the setup process I wouldn't have even tried. Now on to Hello World part 2...
Upvote 0
I didn´t find the answer of the riddle "find out how to include cs-code in MS-Visual Studio". I only got errors like CA1016, CS0246 or CS0103. I could not include code for example MacGruber and could not convince Visual Studio to include it. The more I try the more errors i got.
Upvote 0
*very* useful and will save me a ton of time. I was looking for such a long time on how to code browse with Visual Studio and this article made the difference... thanks and keep 'em coming! :)
Upvote 0
Back
Top Bottom