If you are deploying your game to multiple distribution platforms (e.g. SynthesisVR, Steam, etc) and you are looking for a way to easily deploy new versions across all stores, the Unity Build Scripts is your solution.

Step 1 – under the Asset folder your Unity project, create a new folder called “Editor”:

Step 2 – Inside the “Editor” folder, create and open a new C# Script (you can put your own name):

Step 3 – Use the following file template:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using UnityEditor;
using UnityEditor.Build.Reporting;
using UnityEngine;

class UploadToAllPlatforms
{
   static List<string> allGameScenes = new List<string>() {
        "Assets/AllScenes/MainScene.unity",
        "Assets/AllScenes/Level1.unity",
        "Assets/AllScenes/Level2.unity"
    };
    static string primaryOutputDirectory = @"E:\UnityBUilds\GameName\";
    static Dictionary<string, Platform> allPlatforms = new Dictionary<string, Platform>() { };

    class Cmd
    {
        internal string Path = null;
        internal string Arguments = null;
    }


    class Platform
    {
        internal BuildTarget target = BuildTarget.StandaloneWindows64;
        internal BuildOptions options = BuildOptions.CompressWithLz4HC;
        internal List<string> scenes = allGameScenes; // Adopt your predefined list of scenes or add/remove scenes if necessary:
        internal string output = null;
        internal List<Cmd> onSuccessCommandLineActions = new List<Cmd>();
        internal List<GameObject> platformSpecificObjects = new List<GameObject>();
    }

    static Dictionary<string, Platform> allPlatforms = new Dictionary<string, Platform>() { };

    static void ProcessAllPlatforms() {
    }
}

Step 4 – Start adding per-platform actions to ProcessAllPlatforms(). In the case of SynthesisVR, you would likely have 4 builds – one for PCVR ; one for Quest ; one for Pico and one for HTC Focus 3:

Create a #region that will handle all 4 builds and add some global Synthesis settings to it:

        #region SynthesisVR - All Builds
        
        var synthesisVRcmd = @"""D:\Tools\SynthesisProducer\SynthesisVR - Producer Content Manager.exe""";
        var synthesisVRlogin = "yourdevaccount";
        var synthesisVRpassword = "yourdevaccount_password";
        var synthesisVRgameid = "0000";
        var synthesisVRgameObjects = new List<GameObject>() { GameObject.Find("SynthesisRootObject") };

        #endregion SynthesisVR - All Builds

Step 5.1 – Add the Synthesis PCVR build before the end region:

        #region PCVR Build for SynthesisVR
        var svr_PCVR = new Platform();
        svr_PCVR.platformSpecificObjects = synthesisVRgameObjects;

        // Specify the local folder where the final platform build will be stored:
        svr_PCVR.output = primaryOutputDirectory + @"SynthesisVR\PCVR\GameName.exe";
        
        // Each platform provides it's own set of upload tools.
        svr_PCVR.onSuccessCommandLineActions.Add(new Cmd { 
            Path = synthesisVRcmd,
            Arguments = $"-autologin -autoupload -user={synthesisVRlogin} -pass={synthesisVRpassword} -gameid={synthesisVRgameid} -type=pcvr -basepath=\"" + Path.GetDirectoryName(svr_PCVR.output) + "\" -exe=\"" + Path.GetFileName(svr_PCVR.output) + "\""
        });
        allPlatforms.Add("SynthesisVR_PCVR", svr_PCVR);
        #endregion PCVR Build for SynthesisVR

Step 5.2 – Add the Synthesis Quest standalone build:

        #region Quest Standalone Build for SynthesisVR
        var svr_Android_Quest = new Platform();
        svr_Android_Quest.platformSpecificObjects = synthesisVRgameObjects;

        svr_Android_Quest.output = primaryOutputDirectory + @"SynthesisVR\Quest\GameName.apk";
        svr_Android_Quest.target = BuildTarget.Android;

        svr_Android_Quest.onSuccessCommandLineActions.Add(new Cmd
        {
            Path = synthesisVRcmd,
            Arguments = $"-autologin -autoupload -user={synthesisVRlogin} -pass={synthesisVRpassword} -gameid={synthesisVRgameid} -type=quest -basepath=\"" + svr_Android_Quest.output + "\""
        });

        allPlatforms.Add("SynthesisVR_Quest", svr_Android_Quest);
        #endregion Quest Standalone Build for SynthesisVR

Step 5.3 – Do the same for Pico and Focus 3:

        #region Pico Standalone Build for SynthesisVR
        var svr_Android_Pico = new Platform();
        svr_Android_Pico.platformSpecificObjects = synthesisVRgameObjects;

        svr_Android_Pico.output = primaryOutputDirectory + @"SynthesisVR\Pico\GameName.apk";
        svr_Android_Pico.target = BuildTarget.Android;

        svr_Android_Pico.onSuccessCommandLineActions.Add(new Cmd
        {
            Path = synthesisVRcmd,
            Arguments = $"-autologin -autoupload -user={synthesisVRlogin} -pass={synthesisVRpassword} -gameid={synthesisVRgameid} -type=pico -basepath=\"" + svr_Android_Pico.output + "\""
        });

        allPlatforms.Add("SynthesisVR_Quest", svr_Android_Pico);
        #endregion Pico Standalone Build for SynthesisVR

        #region Focus 3 Standalone Build for SynthesisVR
        var svr_Android_Focus3 = new Platform();
        svr_Android_Focus3.platformSpecificObjects = synthesisVRgameObjects;
        svr_Android_Focus3.output = primaryOutputDirectory + @"SynthesisVR\Focus3\GameName.apk";
        svr_Android_Focus3.target = BuildTarget.Android;

        svr_Android_Focus3.onSuccessCommandLineActions.Add(new Cmd
        {
            Path = synthesisVRcmd,
            Arguments = $"-autologin -autoupload -user={synthesisVRlogin} -pass={synthesisVRpassword} -gameid={synthesisVRgameid} -type=htc -basepath=\"" + svr_Android_Focus3.output + "\""
        });

        allPlatforms.Add("SynthesisVR_Quest", svr_Android_Focus3);
        #endregion Focus 3 Standalone Build for SynthesisVR

This is what your ProcessAllPlatforms() class would look like:

Step 6 – Analogically, create more regions for Steam and other platforms

Step 7 – Create one extra region at the bottom of ProcessAllPlatforms():

        #region Process the builds
        var allCommandLineArguments = System.Environment.GetCommandLineArgs();
        foreach (var platformName in allCommandLineArguments)
        {
            if (allPlatforms.ContainsKey(platformName))
            {
                UnityEngine.Debug.Log($"Building Platform: {platformName}");

                var platform = allPlatforms[platformName];

                if (platform.output != null)
                {
                    if (Directory.Exists(platform.output))
                    {
                        DirectoryInfo di = new DirectoryInfo(platform.output);

                        try
                        {
                            foreach (FileInfo file in di.GetFiles())
                            {
                                file.Delete();
                            }
                        }
                        catch (Exception ex)
                        {
                            UnityEngine.Debug.Log("ERROR: Cleaning up directory failed: " + ex.Message);
                        }


                        try
                        {
                            Directory.Delete(platform.output, true);
                        }
                        catch (Exception e)
                        {
                            UnityEngine.Debug.Log($"Unable to delete directory: {platform.output}");
                        }
                    }

                    // Enable my GameObjects + Disable GameObjects from other platforms
                    foreach (var subPlatform in allPlatforms)
                    {
                        if (subPlatform.Key != platformName)
                        {
                            foreach (var obj in subPlatform.Value.platformSpecificObjects)
                            {
                                obj.SetActive(false);
                            }
                        }
                        else
                        {
                            foreach (var obj in subPlatform.Value.platformSpecificObjects)
                            {
                                obj.SetActive(true);
                            }
                        }
                    }

                    // Perform the actual build:
                    BuildReport report = BuildPipeline.BuildPlayer(platform.scenes.ToArray(), platform.output, platform.target, platform.options);
                    BuildSummary summary = report.summary;

                    if (summary.result == BuildResult.Succeeded)
                    {
                        UnityEngine.Debug.Log($"{platformName} Build succeeded: " + summary.totalSize + " bytes");

                        foreach(var runCmd in platform.onSuccessCommandLineActions)
                        {
                            if (File.Exists(runCmd.Path))
                            {
                                Process cmd = new Process();
                                cmd.StartInfo.FileName = runCmd.Path;
                                cmd.StartInfo.WorkingDirectory = Path.GetDirectoryName(runCmd.Path);
                                cmd.StartInfo.Arguments = runCmd.Arguments ?? "";
                                cmd.Start();
                                cmd.WaitForExit();
                            }
                        }

                    }
                    else if (summary.result == BuildResult.Failed)
                    {
                        UnityEngine.Debug.LogError($"{platformName} Build failed");
                    }
                }
            }
        }
        #endregion Process the builds

Step 7 (FINAL)

Locate the exe of your Unity Editor.

Example: J:\Program Files (x86)\Unity-EditorVR\Editor\Unity.exe

Create a .BAT script somewhere on your PC and put the following line:

"J:\Program Files (x86)\Unity-EditorVR\Editor\Unity.exe" -quit -batchmode -username "UNITY_USER_NAME" -password "UNITY_PASS" -logFile "C:\Unity_Automated_Build.log" -executeMethod UploadToAllPlatforms.ProcessAllPlatforms svr_PCVR svr_Android_Quest svr_Android_Pico svr_Android_Focus3 

Note – you can build just specific platforms by controlling the command line arguments (svr_PCVR ; svr_Android_Quest ; etc)

Launch the BAT file and let it prepare and upload the builds.