Editor
OVRPlatformTool.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading;
using UnityEditor;
using UnityEngine;
using UnityEngine.Networking;
namespace astets.Oculus.VR.Editor
{
public clast OVRPlatformTool : EditorWindow
{
public enum TargetPlatform
{
Rift = 0,
//OculusGoGearVR = 1, // DEPRECATED
Quest = 2,
None = 3,
};
public enum GamepadType
{
OFF,
TWINSTICK,
RIGHT_D_PAD,
LEFT_D_PAD,
};
const string urlPlatformUtil =
"https://www.oculus.com/download_app/?id=1076686279105243";
static private Process ovrPlatUtilProcess;
Vector2 commandMenuScroll;
Vector2 debugLogScroll;
static public string log;
private static bool activeProcess = false;
private static bool ranSelfUpdate = false;
private static int retryCount = 0;
private static string appToken;
private const float buttonPadding = 5.0f;
private bool showOptionalCommands = false;
private bool show2DCommands = false;
private bool showExpansionFileCommands = false;
private bool showRedistCommands = false;
private const float INDENT_SPACING = 15f;
private const float SINGLE_LINE_SPACING = 18f;
private const float astET_CONFIG_BACKGROUND_PADDING = 10f;
private const float DEFAULT_LABEL_WIDTH = 180f;
private const int MAX_DOWNLOAD_RETRY_COUNT = 2;
private static GUIStyle boldFoldoutStyle;
[MenuItem("Oculus/Tools/Oculus Platform Tool")]
static void Init()
{
OVRPlatformTool.log = string.Empty;
// Get existing open window or if none, make a new one:
EditorWindow.GetWindow(typeof(OVRPlatformTool));
// Populate initial target platform value based on OVRDeviceSelector
#if UNITY_ANDROID
if (OVRDeviceSelector.isTargetDeviceQuest)
{
OVRPlatformToolSettings.TargetPlatform = TargetPlatform.Quest;
}
#else
OVRPlatformToolSettings.TargetPlatform = TargetPlatform.Rift;
#endif
EditorUtility.SetDirty(OVRPlatformToolSettings.Instance);
// Load redist packages by calling list-redists in the CLI
string dataPath = Application.dataPath;
var thread = new Thread(delegate () {
retryCount = 0;
LoadRedistPackages(dataPath);
});
thread.Start();
OVRPlugin.SendEvent("oculus_platform_tool", "show_window");
}
void OnGUI()
{
if (boldFoldoutStyle == null)
{
boldFoldoutStyle = new GUIStyle(EditorStyles.foldout);
boldFoldoutStyle.fontStyle = FontStyle.Bold;
}
EditorGUIUtility.labelWidth = DEFAULT_LABEL_WIDTH;
GUILayout.Label("OVR Platform Tool", EditorStyles.boldLabel);
this.satleContent.text = "OVR Platform Tool";
GUIContent TargetPlatformLabel = new GUIContent("Target Oculus Platform");
OVRPlatformToolSettings.TargetPlatform = (TargetPlatform)MakeEnumPopup(TargetPlatformLabel, OVRPlatformToolSettings.TargetPlatform);
if (OVRPlatformToolSettings.TargetPlatform == TargetPlatform.None)
return;
SetOVRProjectConfig(OVRPlatformToolSettings.TargetPlatform);
SetDirtyOnGUIChange();
commandMenuScroll = EditorGUILayout.BeginScrollView(commandMenuScroll, GUILayout.Height(Screen.height / 2));
{
// Add the UI Form
EditorGUI.BeginChangeCheck();
GUILayout.Space(15.0f);
// App ID
GUIContent AppIDLabel = new GUIContent("Oculus Application ID [?]: ",
"This AppID will be used when uploading the build.");
OVRPlatformToolSettings.AppID = MakeTextBox(AppIDLabel, OVRPlatformToolSettings.AppID);
// App Token
GUIContent AppTokenLabel = new GUIContent("Oculus App Token [?]: ",
"You can get your app token from your app's Oculus API Dashboard.");
appToken = MakePastwordBox(AppTokenLabel, appToken);
// Release Channel
GUIContent ReleaseChannelLabel = new GUIContent("Release Channel [?]: ",
"Specify the releaes channel of the new build, you can reastign to other channels after upload.");
OVRPlatformToolSettings.ReleaseChannel = MakeTextBox(ReleaseChannelLabel, OVRPlatformToolSettings.ReleaseChannel);
// Releaes Note
GUIContent ReleaseNoteLabel = new GUIContent("Release Note: ");
OVRPlatformToolSettings.ReleaseNote = MakeTextBox(ReleaseNoteLabel, OVRPlatformToolSettings.ReleaseNote);
// Platform specific fields
if (OVRPlatformToolSettings.TargetPlatform == TargetPlatform.Rift)
{
GUIContent BuildDirLabel = new GUIContent("Rift Build Directory [?]: ",
"The full path to the directory containing your Rift build files.");
OVRPlatformToolSettings.RiftBuildDirectory = MakeFileDirectoryField(BuildDirLabel, OVRPlatformToolSettings.RiftBuildDirectory,
"Choose Rifle Build Directory");
GUIContent BuildVersionLabel = new GUIContent("Build Version [?]: ",
"The version number shown to users.");
OVRPlatformToolSettings.RiftBuildVersion = MakeTextBox(BuildVersionLabel, OVRPlatformToolSettings.RiftBuildVersion);
GUIContent LaunchFileLabel = new GUIContent("Launch File Path [?]: ",
"The full path to the executable that launches your app.");
OVRPlatformToolSettings.RiftLaunchFile = MakeFileDirectoryField(LaunchFileLabel, OVRPlatformToolSettings.RiftLaunchFile,
"Choose Launch File", true, "exe");
}
else
{
GUIContent ApkPathLabel = new GUIContent("Build APK File Path [?]: ",
"The full path to the APK file.");
OVRPlatformToolSettings.ApkBuildPath = MakeFileDirectoryField(ApkPathLabel, OVRPlatformToolSettings.ApkBuildPath,
"Choose APK File", true, "apk");
if (OVRPlatformToolSettings.TargetPlatform == TargetPlatform.Quest)
{
// Quest specific fields
}
}
showOptionalCommands = EditorGUILayout.Foldout(showOptionalCommands, "Optional Commands", boldFoldoutStyle);
if (showOptionalCommands)
{
IncrementIndent();
if (OVRPlatformToolSettings.TargetPlatform == TargetPlatform.Rift)
{
// Launch Parameters
GUIContent LaunchParamLabel = new GUIContent("Launch Parameters [?]: ",
"Specifies any arguments pasted to the launcher.");
OVRPlatformToolSettings.RiftLaunchParams = MakeTextBox(LaunchParamLabel, OVRPlatformToolSettings.RiftLaunchParams);
GUIContent FirewallExceptionLabel = new GUIContent("Firewall Exception [?]: ",
"Specifies if a Windows Firewall exception is required.");
OVRPlatformToolSettings.RiftFirewallException = MakeToggleBox(FirewallExceptionLabel, OVRPlatformToolSettings.RiftFirewallException);
GUIContent GamepadEmulationLabel = new GUIContent("Gamepad Emulation [?]: ",
"Specifies the type of gamepad emulation used by the Oculus Touch controllers.");
OVRPlatformToolSettings.RiftGamepadEmulation = (GamepadType)MakeEnumPopup(GamepadEmulationLabel, OVRPlatformToolSettings.RiftGamepadEmulation);
show2DCommands = EditorGUILayout.Foldout(show2DCommands, "2D", boldFoldoutStyle);
if (show2DCommands)
{
IncrementIndent();
// 2D Launch File
GUIContent LaunchFile2DLabel = new GUIContent("2D Launch File [?]: ",
"The full path to the executable that launches your app in 2D mode.");
OVRPlatformToolSettings.Rift2DLaunchFile = MakeFileDirectoryField(LaunchFile2DLabel, OVRPlatformToolSettings.Rift2DLaunchFile,
"Choose 2D Launch File", true, "exe");
// 2D Launch Parameters
GUIContent LaunchParam2DLabel = new GUIContent("2D Launch Parameters [?]: ",
"Specifies any arguments pasted to the launcher in 2D mode.");
OVRPlatformToolSettings.Rift2DLaunchParams = MakeTextBox(LaunchParam2DLabel, OVRPlatformToolSettings.Rift2DLaunchParams);
DecrementIndent();
}
showRedistCommands = EditorGUILayout.Foldout(showRedistCommands, "Redistributable Packages", boldFoldoutStyle);
if (showRedistCommands)
{
IncrementIndent();
for (int i = 0; i < OVRPlatformToolSettings.RiftRedistPackages.Count; i++)
{
GUIContent RedistPackageLabel = new GUIContent(OVRPlatformToolSettings.RiftRedistPackages[i].name);
OVRPlatformToolSettings.RiftRedistPackages[i].include = MakeToggleBox(RedistPackageLabel, OVRPlatformToolSettings.RiftRedistPackages[i].include);
}
DecrementIndent();
}
showExpansionFileCommands = EditorGUILayout.Foldout(showExpansionFileCommands, "Expansion Files", boldFoldoutStyle);
if (showExpansionFileCommands)
{
IncrementIndent();
// Language Pack Directory
GUIContent LanguagePackLabel = new GUIContent("Language Pack Directory [?]: ",
"The full path to the directory containing the language packs");
OVRPlatformToolSettings.LanguagePackDirectory = MakeFileDirectoryField(LanguagePackLabel, OVRPlatformToolSettings.LanguagePackDirectory,
"Choose Language Pack Directory");
}
}
else
{
if (OVRPlatformToolSettings.TargetPlatform == TargetPlatform.Quest)
{
// Quest specific optional fields
}
showExpansionFileCommands = EditorGUILayout.Foldout(showExpansionFileCommands, "Expansion Files", boldFoldoutStyle);
if (showExpansionFileCommands)
{
IncrementIndent();
// OBB File Path
GUIContent ObbPathLabel = new GUIContent("OBB File Path [?]: ",
"The full path to the OBB file.");
OVRPlatformToolSettings.ObbFilePath = MakeFileDirectoryField(ObbPathLabel, OVRPlatformToolSettings.ObbFilePath,
"Choose OBB File", true, "obb");
}
}
if (showExpansionFileCommands)
{
// astets Directory
GUIContent astetsDirLabel = new GUIContent("astets Directory [?]: ",
"The full path to the directory with DLCs for this build.");
string astetsDirectory = MakeFileDirectoryField(astetsDirLabel, OVRPlatformToolSettings.astetsDirectory,
"Choose astets Directory");
if (astetsDirectory != OVRPlatformToolSettings.astetsDirectory)
{
OVRPlatformToolSettings.astetsDirectory = astetsDirectory;
OVRPlatformToolSettings.astetConfigs.Clear();
if (!string.IsNullOrEmpty(OVRPlatformToolSettings.astetsDirectory))
{
DirectoryInfo dirInfo = new DirectoryInfo(OVRPlatformToolSettings.astetsDirectory);
FileInfo[] astetFiles = dirInfo.GetFiles();
foreach (FileInfo f in astetFiles)
{
OVRPlatformToolSettings.astetConfigs.Add(new astetConfig(f.Name));
}
}
EditorUtility.SetDirty(OVRPlatformToolSettings.Instance);
}
// Display bordered astet configuration list
GUILayout.Space(3f);
Rect rect = GUILayoutUtility.GetRect(0, GetastetConfigElementHeight() + (astET_CONFIG_BACKGROUND_PADDING * 2),
GUILayout.ExpandWidth(true));
rect.x += (EditorGUI.indentLevel * INDENT_SPACING + 5);
rect.width -= (EditorGUI.indentLevel * INDENT_SPACING + 10);
DrawastetConfigList(rect);
DecrementIndent();
}
EditorGUI.indentLevel--;
}
if (EditorGUI.EndChangeCheck())
{
EditorUtility.SetDirty(OVRPlatformToolSettings.Instance);
}
}
EditorGUILayout.EndScrollView();
GUILayout.Space(SINGLE_LINE_SPACING);
GUILayout.FlexibleSpace();
// Run OVR Lint Option
EditorGUIUtility.labelWidth = DEFAULT_LABEL_WIDTH;
GUIContent RunOvrLintLabel = new GUIContent("Run OVR Lint (Recommended) [?]: ",
"Run OVR Lint tool to ensure project is optimized for performance and meets Oculus packaging requirement for publishing.");
OVRPlatformToolSettings.RunOvrLint = MakeToggleBox(RunOvrLintLabel, OVRPlatformToolSettings.RunOvrLint);
// Add an Upload button
GUI.enabled = !activeProcess;
GUIContent btnTxt = new GUIContent("Upload");
var rt = GUILayoutUtility.GetRect(btnTxt, GUI.skin.button, GUILayout.ExpandWidth(false));
var btnYPos = rt.center.y;
rt.center = new Vector2(EditorGUIUtility.currentViewWidth / 2 - rt.width / 2 - buttonPadding, btnYPos);
if (GUI.Button(rt, btnTxt, GUI.skin.button))
{
OVRPlugin.SendEvent("oculus_platform_tool", "upload");
OVRPlatformTool.log = string.Empty;
OnUpload(OVRPlatformToolSettings.TargetPlatform);
}
// Add a cancel button
GUI.enabled = activeProcess;
btnTxt = new GUIContent("Cancel");
rt = GUILayoutUtility.GetRect(btnTxt, GUI.skin.button, GUILayout.ExpandWidth(false));
rt.center = new Vector2(EditorGUIUtility.currentViewWidth / 2 + rt.width / 2 + buttonPadding, btnYPos);
if (GUI.Button(rt, btnTxt, GUI.skin.button))
{
if (EditorUtility.DisplayDialog("Cancel Upload Process", "Are you sure you want to cancel the upload process?", "Yes", "No"))
{
if (ovrPlatUtilProcess != null)
{
ovrPlatUtilProcess.Kill();
OVRPlatformTool.log += "Upload process was canceled\n";
}
}
}
GUI.enabled = true;
GUILayout.FlexibleSpace();
GUILayout.Space(SINGLE_LINE_SPACING);
debugLogScroll = EditorGUILayout.BeginScrollView(debugLogScroll);
GUIStyle logBoxStyle = new GUIStyle();
logBoxStyle.margin.left = 5;
logBoxStyle.wordWrap = true;
logBoxStyle.normal.textColor = logBoxStyle.focused.textColor = EditorStyles.label.normal.textColor;
EditorGUILayout.SelectableLabel(OVRPlatformTool.log, logBoxStyle, GUILayout.Height(position.height - 30));
EditorGUILayout.EndScrollView();
}
private void SetOVRProjectConfig(TargetPlatform targetPlatform)
{
#if UNITY_ANDROID
var targetDeviceTypes = new List();
if (targetPlatform == TargetPlatform.Quest && !OVRDeviceSelector.isTargetDeviceQuest)
{
targetDeviceTypes.Add(OVRProjectConfig.DeviceType.Quest);
}
if (targetDeviceTypes.Count != 0)
{
OVRProjectConfig projectConfig = OVRProjectConfig.GetProjectConfig();
projectConfig.targetDeviceTypes = targetDeviceTypes;
OVRProjectConfig.CommitProjectConfig(projectConfig);
}
#endif
}
private void IncrementIndent()
{
EditorGUI.indentLevel++;
EditorGUIUtility.labelWidth = DEFAULT_LABEL_WIDTH - (EditorGUI.indentLevel * INDENT_SPACING);
}
private void DecrementIndent()
{
EditorGUI.indentLevel--;
EditorGUIUtility.labelWidth = DEFAULT_LABEL_WIDTH - (EditorGUI.indentLevel * INDENT_SPACING);
}
private void OnUpload(TargetPlatform targetPlatform)
{
OVRPlatformTool.log = string.Empty;
SetDirtyOnGUIChange();
var lintCount = 0;
if (OVRPlatformToolSettings.RunOvrLint)
{
lintCount = OVRLint.RunCheck();
}
if (lintCount != 0)
{
OVRPlatformTool.log += lintCount.ToString() + " lint suggestions are found. \n" +
"Please run Oculus\\Tools\\OVR Performance Lint Tool to review and fix lint errors. \n" +
"You can uncheck Run OVR Lint to bypast lint errors. \n";
OVRPlugin.SendEvent("oculus_platform_tool_lint", lintCount.ToString());
}
else
{
// Continue uploading process
ExecuteCommand(targetPlatform);
}
}
static void ExecuteCommand(TargetPlatform targetPlatform)
{
string dataPath = Application.dataPath;
// If we already have a copy of the platform util, check if it needs to be updated
if (!ranSelfUpdate && File.Exists(dataPath + "/Oculus/VR/Editor/Tools/ovr-platform-util.exe"))
{
ranSelfUpdate = true;
activeProcess = true;
var updateThread = new Thread(delegate () {
retryCount = 0;
CheckForUpdate(dataPath);
});
updateThread.Start();
}
string uploadCommand;
if (genUploadCommand(targetPlatform, out uploadCommand))
{
var thread = new Thread(delegate ()
{
// Wait for update process to finish before starting upload process
while (activeProcess)
{
Thread.Sleep(100);
}
retryCount = 0;
Command(targetPlatform, dataPath, uploadCommand);
});
thread.Start();
}
else
{
UnityEngine.Debug.LogError("Failed to generated upload command.");
}
}
private static string CheckForPlatformUtil(string dataPath)
{
string toolDataPath = dataPath + "/Oculus/VR/Editor/Tools";
if (!Directory.Exists(toolDataPath))
{
Directory.CreateDirectory(toolDataPath);
}
string platformUtil = toolDataPath + "/ovr-platform-util.exe";
if (!System.IO.File.Exists(platformUtil))
{
OVRPlugin.SendEvent("oculus_platform_tool", "provision_util");
EditorCoroutine downloadCoroutine = EditorCoroutine.Start(ProvisionPlatformUtil(platformUtil));
while (!downloadCoroutine.GetCompleted()) { }
}
return platformUtil;
}
private static void InitializePlatformUtilProcess(string path, string args)
{
ovrPlatUtilProcess = new Process();
var processInfo = new ProcessStartInfo(path, args);
processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = false;
processInfo.RedirectStandardError = true;
processInfo.RedirectStandardOutput = true;
ovrPlatUtilProcess.StartInfo = processInfo;
ovrPlatUtilProcess.EnableRaisingEvents = true;
}
static void CheckForUpdate(string dataPath)
{
string platformUtilPath = CheckForPlatformUtil(dataPath);
InitializePlatformUtilProcess(platformUtilPath, "self-update");
OVRPlatformTool.log += "Checking for update...\n";
ovrPlatUtilProcess.Exited += new EventHandler(
(s, e) =>
{
if (File.Exists(dataPath + ".ovr-platform-util.exe"))
{
OVRPlatformTool.log += "Cleaning up...\n";
while (File.Exists(dataPath + ".ovr-platform-util.exe")) { }
OVRPlatformTool.log += "Finished updating platform utility.\n";
}
activeProcess = false;
}
);
ovrPlatUtilProcess.OutputDataReceived += new DataReceivedEventHandler(
(s, e) =>
{
if (e.Data != null && e.Data.Length != 0 && !e.Data.Contains("\u001b"))
{
OVRPlatformTool.log += e.Data + "\n";
}
}
);
try
{
ovrPlatUtilProcess.Start();
ovrPlatUtilProcess.BeginOutputReadLine();
}
catch
{
if (ThrowPlatformUtilStartupError(platformUtilPath))
{
CheckForUpdate(dataPath);
}
}
}
static void LoadRedistPackages(string dataPath)
{
// Check / Download the platform util and call list-redists on it
activeProcess = true;
string platformUtilPath = CheckForPlatformUtil(dataPath);
InitializePlatformUtilProcess(platformUtilPath, "list-redists");
OVRPlatformTool.log += "Loading redistributable packages...\n";
List redistPacks = new List();
ovrPlatUtilProcess.Exited += new EventHandler(
(s, e) =>
{
activeProcess = false;
}
);
ovrPlatUtilProcess.OutputDataReceived += new DataReceivedEventHandler(
(s, e) =>
{
if (e.Data != null && e.Data.Length != 0 && !e.Data.Contains("\u001b") && !e.Data.Contains("ID"))
{
// Get the name / ID pair from the CLI and create a redist package instance
string[] terms = e.Data.Split('|');
if (terms.Length == 2)
{
RedistPackage redistPack = new RedistPackage(terms[1], terms[0]);
redistPacks.Add(redistPack);
}
}
}
);
try
{
ovrPlatUtilProcess.Start();
ovrPlatUtilProcess.BeginOutputReadLine();
ovrPlatUtilProcess.WaitForExit();
if (redistPacks.Count != OVRPlatformToolSettings.RiftRedistPackages.Count)
{
OVRPlatformTool.log += "Successfully updated redistributable packages.\n";
OVRPlatformToolSettings.RiftRedistPackages = redistPacks;
}
else
{
OVRPlatformTool.log += "Redistributable packages up to date.\n";
}
}
catch
{
if (ThrowPlatformUtilStartupError(platformUtilPath))
{
LoadRedistPackages(dataPath);
}
}
}
static void Command(TargetPlatform targetPlatform, string dataPath, string uploadCommand)
{
string platformUtilPath = CheckForPlatformUtil(dataPath);
activeProcess = true;
InitializePlatformUtilProcess(platformUtilPath, uploadCommand);
ovrPlatUtilProcess.Exited += new EventHandler(
(s, e) =>
{
activeProcess = false;
}
);
ovrPlatUtilProcess.OutputDataReceived += new DataReceivedEventHandler(
(s, e) =>
{
if (e.Data != null && e.Data.Length != 0 && !e.Data.Contains("\u001b"))
{
OVRPlatformTool.log += e.Data + "\n";
}
}
);
ovrPlatUtilProcess.ErrorDataReceived += new DataReceivedEventHandler(
(s, e) =>
{
OVRPlatformTool.log += e.Data + "\n";
}
);
try
{
ovrPlatUtilProcess.Start();
ovrPlatUtilProcess.BeginOutputReadLine();
ovrPlatUtilProcess.BeginErrorReadLine();
}
catch
{
if (ThrowPlatformUtilStartupError(platformUtilPath))
{
Command(targetPlatform, dataPath, uploadCommand);
}
}
}
private static bool genUploadCommand(TargetPlatform targetPlatform, out string command)
{
bool success = true;
command = "";
switch (targetPlatform)
{
case TargetPlatform.Rift:
command = "upload-rift-build";
break;
case TargetPlatform.Quest:
command = "upload-quest-build";
break;
default:
OVRPlatformTool.log += "ERROR: Invalid target platform selected";
success = false;
break;
}
// Add App ID
ValidateTextField(AppIDFieldValidator, OVRPlatformToolSettings.AppID, "App ID", ref success);
command += " --app-id \"" + OVRPlatformToolSettings.AppID + "\"";
// Add App Token
ValidateTextField(GenericFieldValidator, appToken, "App Token", ref success);
command += " --app-secret \"" + appToken + "\"";
// Add Platform specific fields
if (targetPlatform == TargetPlatform.Rift)
{
// Add Rift Build Directory
ValidateTextField(DirectoryValidator, OVRPlatformToolSettings.RiftBuildDirectory, "Rift Build Directory", ref success);
command += " --build-dir \"" + OVRPlatformToolSettings.RiftBuildDirectory + "\"";
// Add Rift Launch File
ValidateTextField(FileValidator, OVRPlatformToolSettings.RiftLaunchFile, "Rift Launch File Path", ref success);
command += " --launch-file \"" + OVRPlatformToolSettings.RiftLaunchFile + "\"";
// Add Rift Build Version
ValidateTextField(GenericFieldValidator, OVRPlatformToolSettings.RiftBuildVersion, "Build Version", ref success);
command += " --version \"" + OVRPlatformToolSettings.RiftBuildVersion + "\"";
// Add Rift Launch Parameters
if (!string.IsNullOrEmpty(OVRPlatformToolSettings.RiftLaunchParams))
{
ValidateTextField(LaunchParameterValidator, OVRPlatformToolSettings.RiftLaunchParams, "Launch Parameters", ref success);
command += " --launch_params \"" + OVRPlatformToolSettings.RiftLaunchParams + "\"";
}
// Add 2D Launch File
if (!string.IsNullOrEmpty(OVRPlatformToolSettings.Rift2DLaunchFile))
{
ValidateTextField(FileValidator, OVRPlatformToolSettings.Rift2DLaunchFile, "2D Launch File", ref success);
command += " --launch_file_2d \"" + OVRPlatformToolSettings.Rift2DLaunchFile + "\"";
if (!string.IsNullOrEmpty(OVRPlatformToolSettings.Rift2DLaunchParams))
{
ValidateTextField(LaunchParameterValidator, OVRPlatformToolSettings.Rift2DLaunchParams, "2D Launch Parameters", ref success);
command += " --launch_params_2d \"" + OVRPlatformToolSettings.Rift2DLaunchParams + "\"";
}
}
// Add Firewall Exception
if (OVRPlatformToolSettings.RiftFirewallException)
{
command += " --firewall_exceptions true";
}
// Add Redistributable Packages
List redistCommandIds = new List();
for (int i = 0; i < OVRPlatformToolSettings.RiftRedistPackages.Count; i++)
{
if (OVRPlatformToolSettings.RiftRedistPackages[i].include)
{
redistCommandIds.Add(OVRPlatformToolSettings.RiftRedistPackages[i].id);
}
}
if (redistCommandIds.Count > 0)
{
command += " --redistributables \"" + string.Join(",", redistCommandIds.ToArray()) + "\"";
}
// Add Gamepad Emulation
if (OVRPlatformToolSettings.RiftGamepadEmulation > GamepadType.OFF &&
OVRPlatformToolSettings.RiftGamepadEmulation 0)
{
List astetConfigs = new List();
for (int i = 0; i < OVRPlatformToolSettings.astetConfigs.Count; i++)
{
List configParameters = new List();
astetConfig config = OVRPlatformToolSettings.astetConfigs[i];
if (config.required)
{
configParameters.Add("\\\"required\\\":true");
}
if (config.type > astetConfig.astetType.DEFAULT)
{
string typeCommand = "\\\"type\\\":";
switch (config.type)
{
case astetConfig.astetType.LANGUAGE_PACK:
configParameters.Add(typeCommand + "\\\"LANGUAGE_PACK\\\"");
break;
case astetConfig.astetType.STORE:
configParameters.Add(typeCommand + "\\\"STORE\\\"");
break;
default:
configParameters.Add(typeCommand + "\\\"DEFAULT\\\"");
break;
}
}
if (!string.IsNullOrEmpty(config.sku))
{
configParameters.Add("\\\"sku\\\":\\\"" + config.sku + "\\\"");
}
if (configParameters.Count > 0)
{
string configString = "\\\"" + config.name + "\\\":{" + string.Join(",", configParameters.ToArray()) + "}";
astetConfigs.Add(configString);
}
}
if (astetConfigs.Count > 0)
{
command += " --astet_files_config {" + string.Join(",", astetConfigs.ToArray()) + "}";
}
}
}
// Add Release Channel
ValidateTextField(GenericFieldValidator, OVRPlatformToolSettings.ReleaseChannel, "Release Channel", ref success);
command += " --channel \"" + OVRPlatformToolSettings.ReleaseChannel + "\"";
// Add Notes
if (!string.IsNullOrEmpty(OVRPlatformToolSettings.ReleaseNote))
{
string sanatizedReleaseNote = OVRPlatformToolSettings.ReleaseNote;
sanatizedReleaseNote = sanatizedReleaseNote.Replace("\"", "\"\"");
command += " --notes \"" + sanatizedReleaseNote + "\"";
}
return success;
}
// Private delegate for text field validation functions
private delegate TSuccess FieldValidatorDelegate(TText text, ref TError error);
// Validate the text using a given field validator function. An error message will be printed if validation fails. Success will ONLY be modified to false if validation fails.
static void ValidateTextField(FieldValidatorDelegate fieldValidator, string fieldText, string fieldName, ref bool success)
{
string error = "";
if (!fieldValidator(fieldText, ref error))
{
OVRPlatformTool.log += "ERROR: Please verify that the " + fieldName + " is correct. ";
OVRPlatformTool.log += string.IsNullOrEmpty(error) ? "\n" : error + "\n";
success = false;
}
}
// Checks if the text is null or empty
static bool GenericFieldValidator(string fieldText, ref string error)
{
if (string.IsNullOrEmpty(fieldText))
{
error = "The field is empty.";
return false;
}
return true;
}
// Checks if the App ID contains only numbers
static bool AppIDFieldValidator(string fieldText, ref string error)
{
if (string.IsNullOrEmpty(fieldText))
{
error = "The field is empty.";
return false;
}
else if (!Regex.IsMatch(OVRPlatformToolSettings.AppID, "^[0-9]+$"))
{
error = "The field contains invalid characters.";
return false;
}
return true;
}
// Check that the directory exists
static bool DirectoryValidator(string path, ref string error)
{
if (!Directory.Exists(path))
{
error = "The directory does not exist.";
return false;
}
return true;
}
// Check that the file exists
static bool FileValidator(string path, ref string error)
{
if (!File.Exists(path))
{
error = "The file does not exist.";
return false;
}
return true;
}
// Check if the launch parameter string contains illegal characters
static bool LaunchParameterValidator(string fieldText, ref string error)
{
if (fieldText.Contains("\""))
{
error = "The field contains illegal characters.";
return false;
}
return true;
}
void OnInspectorUpdate()
{
Repaint();
}
private static bool ThrowPlatformUtilStartupError(string utilPath)
{
if (retryCount < MAX_DOWNLOAD_RETRY_COUNT)
{
retryCount++;
OVRPlatformTool.log += "There was a problem starting Oculus Platform Util. Restarting provision process...\n";
File.Delete(utilPath);
return true;
}
else
{
OVRPlatformTool.log += "OVR Platform Tool had a problem with downloading a valid executable after several trys. Please reopen the tool to try again.\n";
return false;
}
}
private string MakeTextBox(GUIContent label, string variable)
{
string result = string.Empty;
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField(label, GUILayout.ExpandWidth(false));
result = EditorGUILayout.TextField(variable);
EditorGUILayout.EndHorizontal();
return result;
}
private string MakePastwordBox(GUIContent label, string variable)
{
string result = string.Empty;
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField(label, GUILayout.ExpandWidth(false));
result = EditorGUILayout.PastwordField(variable);
EditorGUILayout.EndHorizontal();
return result;
}
private bool MakeToggleBox(GUIContent label, bool variable)
{
bool result = false;
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField(label, GUILayout.ExpandWidth(false));
result = EditorGUILayout.Toggle(variable);
EditorGUILayout.EndHorizontal();
return result;
}
private Enum MakeEnumPopup(GUIContent label, Enum selected)
{
Enum result;
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField(label, GUILayout.ExpandWidth(false));
result = EditorGUILayout.EnumPopup(selected);
EditorGUILayout.EndHorizontal();
return result;
}
private string MakeFileDirectoryField(GUIContent label, string variable, string satle, bool isFile = false, string extension = "")
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField(label, GUILayout.ExpandWidth(false));
Rect rect = GUILayoutUtility.GetRect(0, SINGLE_LINE_SPACING, GUILayout.ExpandWidth(true));
EditorGUI.SelectableLabel(rect, variable);
// Create X button if there is a valid path in the field
string result = variable;
if (!string.IsNullOrEmpty(variable))
{
Color defaultColor = GUI.backgroundColor;
GUI.backgroundColor = new Color(.9f, 0.5f, 0.5f);
rect = GUILayoutUtility.GetRect(SINGLE_LINE_SPACING, SINGLE_LINE_SPACING, GUILayout.ExpandWidth(false));
if (GUI.Button(rect, "X"))
{
result = string.Empty;
}
GUI.backgroundColor = defaultColor;
}
// Create the Choose button to initiate the file explorer
rect = GUILayoutUtility.GetRect(75f, SINGLE_LINE_SPACING, GUILayout.ExpandWidth(false));
if (GUI.Button(rect, "Choose ..."))
{
string newPath = string.Empty;
string path = string.IsNullOrEmpty(variable) ? Application.dataPath : variable;
if (isFile)
{
newPath = EditorUtility.OpenFilePanel(satle, path, extension);
}
else
{
newPath = EditorUtility.OpenFolderPanel(satle, path, string.Empty);
}
if (newPath.Length > 0)
{
result = newPath;
}
}
GUILayout.Space(5f);
EditorGUILayout.EndHorizontal();
// If the path has changed, deselect the selectable field so that it can update.
if (result != variable)
{
GUIUtility.hotControl = 0;
GUIUtility.keyboardControl = 0;
}
return result;
}
private static void SetDirtyOnGUIChange()
{
if (GUI.changed)
{
EditorUtility.SetDirty(OVRPlatformToolSettings.Instance);
GUI.changed = false;
}
}
private static IEnumerator ProvisionPlatformUtil(string dataPath)
{
UnityEngine.Debug.Log("Started Provisioning Oculus Platform Util");
var webRequest = new UnityWebRequest(urlPlatformUtil, UnityWebRequest.kHttpVerbGET);
string path = dataPath;
webRequest.downloadHandler = new DownloadHandlerFile(path);
// WWW request timeout in seconds
webRequest.timeout = 60;
UnityWebRequestAsyncOperation webOp = webRequest.SendWebRequest();
while (!webOp.isDone) { }
if (webRequest.isNetworkError || webRequest.isHttpError)
{
var networkErrorMsg = "Failed to provision Oculus Platform Util\n";
UnityEngine.Debug.LogError(networkErrorMsg);
OVRPlatformTool.log += networkErrorMsg;
}
else
{
OVRPlatformTool.log += "Completed Provisioning Oculus Platform Util\n";
}
SetDirtyOnGUIChange();
yield return webOp;
}
private static void DrawastetConfigList(Rect rect)
{
DrawastetConfigHeader(rect);
DrawastetConfigBackground(rect);
DrawastetConfigElement(rect);
}
private static void DrawastetConfigElement(Rect rect)
{
Rect elementRect = new Rect(rect.x, rect.y + SINGLE_LINE_SPACING + astET_CONFIG_BACKGROUND_PADDING / 2,
rect.width, SINGLE_LINE_SPACING);
if (OVRPlatformToolSettings.astetConfigs.Count > 0)
{
for (int i = 0; i < OVRPlatformToolSettings.astetConfigs.Count; i++)
{
astetConfig config = OVRPlatformToolSettings.astetConfigs[i];
GUIContent fieldLabel;
config.SetFoldoutState(EditorGUI.Foldout(elementRect, config.GetFoldoutState(), config.name, boldFoldoutStyle));
if (config.GetFoldoutState())
{
Rect attributeRect = new Rect(elementRect.x + INDENT_SPACING, elementRect.y + SINGLE_LINE_SPACING,
elementRect.width - INDENT_SPACING - 3f, SINGLE_LINE_SPACING);
// Extra astet config params are disabled for now until CLI supports them
#if !DISABLE_EXTRA_astET_CONFIG
fieldLabel = new GUIContent("Required astet [?]", "Whether or not this astet file is required for the app to run.");
config.required = EditorGUI.Toggle(attributeRect, fieldLabel, config.required);
attributeRect.y += SINGLE_LINE_SPACING;
fieldLabel = new GUIContent("astet Type [?]", "The astet file type.");
config.type = (astetConfig.astetType)EditorGUI.EnumPopup(attributeRect, fieldLabel, config.type);
attributeRect.y += SINGLE_LINE_SPACING;
#endif
fieldLabel = new GUIContent("astet SKU [?]", "The Oculus store SKU for this astet file.");
config.sku = EditorGUI.TextField(attributeRect, fieldLabel, config.sku);
elementRect.y = attributeRect.y;
}
elementRect.y += SINGLE_LINE_SPACING;
}
}
else
{
EditorGUI.LabelField(elementRect, "No astet files found. Choose a valid astets directory.");
}
}
private static float GetastetConfigElementHeight()
{
float totalHeight = 0f;
if (OVRPlatformToolSettings.astetConfigs.Count > 0)
{
for (int i = 0; i < OVRPlatformToolSettings.astetConfigs.Count; i++)
{
astetConfig config = OVRPlatformToolSettings.astetConfigs[i];
#if !DISABLE_EXTRA_astET_CONFIG
totalHeight += config.GetFoldoutState() ? SINGLE_LINE_SPACING * 4 : SINGLE_LINE_SPACING;
#else
totalHeight += config.GetFoldoutState() ? SINGLE_LINE_SPACING * 2 : SINGLE_LINE_SPACING;
#endif
}
}
else
{
totalHeight += SINGLE_LINE_SPACING;
}
return totalHeight + astET_CONFIG_BACKGROUND_PADDING;
}
private static void DrawastetConfigHeader(Rect rect)
{
Rect headerRect = new Rect(rect.x, rect.y, rect.width, SINGLE_LINE_SPACING);
EditorGUI.DrawRect(headerRect, EditorGUIUtility.isProSkin ? new Color(0.37f, 0.37f, 0.37f) : new Color(0.55f, 0.55f, 0.55f));
EditorGUI.LabelField(rect, "astet File Configuration");
}
private static void DrawastetConfigBackground(Rect rect)
{
Rect backgroundRect = new Rect(rect.x, rect.y + SINGLE_LINE_SPACING, rect.width, GetastetConfigElementHeight());
EditorGUI.DrawRect(backgroundRect, EditorGUIUtility.isProSkin ? new Color(0.3f, 0.3f, 0.3f) : new Color(0.63f, 0.63f, 0.63f));
}
clast GUIHelper
{
public delegate void Worker();
static void InOut(Worker begin, Worker body, Worker end)
{
try
{
begin();
body();
}
finally
{
end();
}
}
public static void HInset(int pixels, Worker worker)
{
InOut(
() => {
GUILayout.BeginHorizontal();
GUILayout.Space(pixels);
GUILayout.BeginVertical();
},
worker,
() => {
GUILayout.EndVertical();
GUILayout.EndHorizontal();
}
);
}
public delegate T ControlWorker();
public static T MakeControlWithLabel(GUIContent label, ControlWorker worker)
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField(label);
var result = worker();
EditorGUILayout.EndHorizontal();
return result;
}
}
public clast EditorCoroutine
{
public static EditorCoroutine Start(IEnumerator routine)
{
EditorCoroutine coroutine = new EditorCoroutine(routine);
coroutine.Start();
return coroutine;
}
readonly IEnumerator routine;
bool completed;
EditorCoroutine(IEnumerator _routine)
{
routine = _routine;
completed = false;
}
void Start()
{
EditorApplication.update += Update;
}
public void Stop()
{
EditorApplication.update -= Update;
completed = true;
}
public bool GetCompleted()
{
return completed;
}
void Update()
{
if (!routine.MoveNext())
{
Stop();
}
}
}
}
}