Assignment for RMIT Mixed Reality in 2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

447 lines
22 KiB

namespace VRTK
{
using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
using System;
using System.Collections.Generic;
using System.Linq;
[CustomEditor(typeof(VRTK_SDKManager))]
public class VRTK_SDKManagerEditor : Editor
{
private static readonly Dictionary<BuildTargetGroup, bool> isBuildTargetActiveSymbolsFoldOut;
private ReorderableList setupsList;
static VRTK_SDKManagerEditor()
{
BuildTargetGroup[] targetGroups = VRTK_SharedMethods.GetValidBuildTargetGroups();
isBuildTargetActiveSymbolsFoldOut = new Dictionary<BuildTargetGroup, bool>(targetGroups.Length);
foreach (BuildTargetGroup targetGroup in targetGroups)
{
isBuildTargetActiveSymbolsFoldOut[targetGroup] = true;
}
}
protected virtual void OnEnable()
{
VRTK_SDKManager sdkManager = (VRTK_SDKManager)target;
setupsList = new ReorderableList(serializedObject, serializedObject.FindProperty("setups"))
{
headerHeight = 2,
drawElementCallback = (rect, index, active, focused) =>
{
SerializedProperty serializedProperty = setupsList.serializedProperty;
if (serializedProperty.arraySize <= index)
{
return;
}
rect.y += 2;
rect.height = EditorGUIUtility.singleLineHeight;
Color previousColor = GUI.color;
if (IsSDKSetupNeverUsed(index))
{
GUI.color = new Color(previousColor.r, previousColor.g, previousColor.b, 0.5f);
}
GUIContent unloadButtonGUIContent = new GUIContent("Unload", "Unload this SDK Setup.");
GUIContent loadButtonGUIContent = new GUIContent("Load", "Try to load this SDK Setup.");
float buttonGUIContentWidth = Mathf.Max(
GUI.skin.button.CalcSize(unloadButtonGUIContent).x,
GUI.skin.button.CalcSize(loadButtonGUIContent).x
);
VRTK_SDKSetup setup = (VRTK_SDKSetup)serializedProperty.GetArrayElementAtIndex(index).objectReferenceValue;
if (EditorApplication.isPlaying && setup != null)
{
rect.width -= buttonGUIContentWidth + ReorderableList.Defaults.padding;
}
EditorGUI.BeginChangeCheck();
EditorGUI.PropertyField(rect,
serializedProperty.GetArrayElementAtIndex(index),
GUIContent.none);
if (EditorGUI.EndChangeCheck())
{
setup = (VRTK_SDKSetup)serializedProperty.GetArrayElementAtIndex(index).objectReferenceValue;
if (setup != null)
{
int indexOfExistingDuplicateSetup = Enumerable
.Range(0, serializedProperty.arraySize)
.Except(new[] { index })
.Where(i => (VRTK_SDKSetup)serializedProperty.GetArrayElementAtIndex(i).objectReferenceValue == setup)
.DefaultIfEmpty(-1)
.First();
if (indexOfExistingDuplicateSetup != -1)
{
serializedProperty.GetArrayElementAtIndex(indexOfExistingDuplicateSetup).objectReferenceValue = null;
setupsList.index = indexOfExistingDuplicateSetup;
ReorderableList.defaultBehaviours.DoRemoveButton(setupsList);
setupsList.index = index;
}
}
sdkManager.ManageVRSettings(false);
}
GUI.color = previousColor;
if (EditorApplication.isPlaying && setup != null)
{
rect.x += rect.width + ReorderableList.Defaults.padding;
rect.width = buttonGUIContentWidth;
if (sdkManager.loadedSetup == setup)
{
if (GUI.Button(rect, unloadButtonGUIContent))
{
sdkManager.UnloadSDKSetup();
}
}
else
{
if (GUI.Button(rect, loadButtonGUIContent))
{
sdkManager.TryLoadSDKSetup(index, true, sdkManager.setups);
}
}
}
},
onAddCallback = list =>
{
SerializedProperty serializedProperty = list.serializedProperty;
int index = serializedProperty.arraySize;
serializedProperty.arraySize++;
list.index = index;
SerializedProperty element = serializedProperty.GetArrayElementAtIndex(index);
element.objectReferenceValue = null;
sdkManager.ManageVRSettings(false);
},
onRemoveCallback = list =>
{
int index = list.index;
VRTK_SDKSetup sdkSetup = sdkManager.setups[index];
bool isLoaded = sdkManager.loadedSetup == sdkSetup;
if (isLoaded)
{
sdkManager.UnloadSDKSetup();
}
if (sdkSetup != null)
{
list.serializedProperty.GetArrayElementAtIndex(index).objectReferenceValue = null;
}
ReorderableList.defaultBehaviours.DoRemoveButton(list);
sdkManager.ManageVRSettings(false);
},
onReorderCallback = list => sdkManager.ManageVRSettings(false)
};
Undo.undoRedoPerformed += UndoRedoPerformed;
}
protected virtual void OnDisable()
{
Undo.undoRedoPerformed -= UndoRedoPerformed;
setupsList = null;
}
public override void OnInspectorGUI()
{
serializedObject.Update();
VRTK_SDKManager sdkManager = (VRTK_SDKManager)target;
const string manageNowButtonText = "Manage Now";
using (new EditorGUILayout.VerticalScope("Box"))
{
VRTK_EditorUtilities.AddHeader("Scripting Define Symbols", false);
using (new EditorGUILayout.HorizontalScope())
{
EditorGUI.BeginChangeCheck();
bool autoManage = EditorGUILayout.Toggle(
VRTK_EditorUtilities.BuildGUIContent<VRTK_SDKManager>("autoManageScriptDefines", "Auto Manage"),
sdkManager.autoManageScriptDefines,
GUILayout.ExpandWidth(false)
);
if (EditorGUI.EndChangeCheck())
{
serializedObject.FindProperty("autoManageScriptDefines").boolValue = autoManage;
serializedObject.ApplyModifiedProperties();
sdkManager.ManageScriptingDefineSymbols(false, true);
}
using (new EditorGUI.DisabledGroupScope(sdkManager.autoManageScriptDefines))
{
GUIContent manageNowGUIContent = new GUIContent(
manageNowButtonText,
"Manage the scripting define symbols defined by the installed SDKs."
+ (sdkManager.autoManageScriptDefines
? "\n\nThis button is disabled because the SDK Manager is set up to manage the scripting define symbols automatically."
+ " Disable the checkbox on the left to allow managing them manually instead."
: "")
);
if (GUILayout.Button(manageNowGUIContent, GUILayout.MaxHeight(GUI.skin.label.CalcSize(manageNowGUIContent).y)))
{
sdkManager.ManageScriptingDefineSymbols(true, true);
}
}
}
using (new EditorGUILayout.VerticalScope("Box"))
{
VRTK_EditorUtilities.AddHeader("Active Symbols Without SDK Classes", false);
VRTK_SDKInfo[] availableSDKInfos = VRTK_SDKManager
.AvailableSystemSDKInfos
.Concat(VRTK_SDKManager.AvailableBoundariesSDKInfos)
.Concat(VRTK_SDKManager.AvailableHeadsetSDKInfos)
.Concat(VRTK_SDKManager.AvailableControllerSDKInfos)
.ToArray();
HashSet<string> sdkSymbols = new HashSet<string>(availableSDKInfos.Select(info => info.description.symbol));
IGrouping<BuildTargetGroup, VRTK_SDKManager.ScriptingDefineSymbolPredicateInfo>[] availableGroupedPredicateInfos = VRTK_SDKManager
.AvailableScriptingDefineSymbolPredicateInfos
.GroupBy(info => info.attribute.buildTargetGroup)
.ToArray();
foreach (IGrouping<BuildTargetGroup, VRTK_SDKManager.ScriptingDefineSymbolPredicateInfo> grouping in availableGroupedPredicateInfos)
{
VRTK_SDKManager.ScriptingDefineSymbolPredicateInfo[] possibleActiveInfos = grouping
.Where(info => !sdkSymbols.Contains(info.attribute.symbol)
&& grouping.Except(new[] { info })
.All(predicateInfo => !(predicateInfo.methodInfo == info.methodInfo
&& sdkSymbols.Contains(predicateInfo.attribute.symbol))))
.OrderBy(info => info.attribute.symbol)
.ToArray();
if (possibleActiveInfos.Length == 0)
{
continue;
}
EditorGUI.indentLevel++;
BuildTargetGroup targetGroup = grouping.Key;
isBuildTargetActiveSymbolsFoldOut[targetGroup] = EditorGUI.Foldout(
EditorGUILayout.GetControlRect(),
isBuildTargetActiveSymbolsFoldOut[targetGroup],
targetGroup.ToString(),
true
);
if (isBuildTargetActiveSymbolsFoldOut[targetGroup])
{
foreach (VRTK_SDKManager.ScriptingDefineSymbolPredicateInfo predicateInfo in possibleActiveInfos)
{
int symbolIndex = sdkManager
.activeScriptingDefineSymbolsWithoutSDKClasses
.FindIndex(attribute => attribute.symbol == predicateInfo.attribute.symbol);
string symbolLabel = predicateInfo.attribute.symbol.Remove(
0,
SDK_ScriptingDefineSymbolPredicateAttribute.RemovableSymbolPrefix.Length
);
if (!(bool)predicateInfo.methodInfo.Invoke(null, null))
{
symbolLabel += " (not installed)";
}
EditorGUI.BeginChangeCheck();
bool isSymbolActive = EditorGUILayout.ToggleLeft(symbolLabel, symbolIndex != -1);
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(sdkManager, "Active Symbol Change");
if (isSymbolActive)
{
sdkManager.activeScriptingDefineSymbolsWithoutSDKClasses.Add(predicateInfo.attribute);
}
else
{
sdkManager.activeScriptingDefineSymbolsWithoutSDKClasses.RemoveAt(symbolIndex);
}
sdkManager.ManageScriptingDefineSymbols(false, true);
}
}
}
EditorGUI.indentLevel--;
}
}
VRTK_EditorUtilities.DrawUsingDestructiveStyle(GUI.skin.button, style =>
{
GUIContent clearSymbolsGUIContent = new GUIContent(
"Remove All Symbols",
"Remove all scripting define symbols of VRTK. This is handy if you removed the SDK files from your project but still have"
+ " the symbols defined which results in compile errors."
+ "\nIf you have the above checkbox enabled the symbols will be managed automatically after clearing them. Otherwise hit the"
+ " '" + manageNowButtonText + "' button to add the symbols for the currently installed SDKs again."
);
if (GUILayout.Button(clearSymbolsGUIContent, style))
{
BuildTargetGroup[] targetGroups = VRTK_SharedMethods.GetValidBuildTargetGroups();
foreach (BuildTargetGroup targetGroup in targetGroups)
{
string[] currentSymbols = PlayerSettings.GetScriptingDefineSymbolsForGroup(targetGroup)
.Split(';')
.Distinct()
.OrderBy(symbol => symbol, StringComparer.Ordinal)
.ToArray();
string[] newSymbols = currentSymbols
.Where(symbol => !symbol.StartsWith(SDK_ScriptingDefineSymbolPredicateAttribute.RemovableSymbolPrefix, StringComparison.Ordinal))
.ToArray();
if (currentSymbols.SequenceEqual(newSymbols))
{
continue;
}
PlayerSettings.SetScriptingDefineSymbolsForGroup(targetGroup, string.Join(";", newSymbols));
string[] removedSymbols = currentSymbols.Except(newSymbols).ToArray();
if (removedSymbols.Length > 0)
{
VRTK_Logger.Info(VRTK_Logger.GetCommonMessage(VRTK_Logger.CommonMessageKeys.SCRIPTING_DEFINE_SYMBOLS_REMOVED, targetGroup, string.Join(", ", removedSymbols)));
}
}
}
});
}
using (new EditorGUILayout.VerticalScope("Box"))
{
VRTK_EditorUtilities.AddHeader("Script Aliases", false);
EditorGUILayout.PropertyField(
serializedObject.FindProperty("scriptAliasLeftController"),
VRTK_EditorUtilities.BuildGUIContent<VRTK_SDKManager>("scriptAliasLeftController", "Left Controller")
);
EditorGUILayout.PropertyField(
serializedObject.FindProperty("scriptAliasRightController"),
VRTK_EditorUtilities.BuildGUIContent<VRTK_SDKManager>("scriptAliasRightController", "Right Controller")
);
}
using (new EditorGUILayout.VerticalScope("Box"))
{
VRTK_EditorUtilities.AddHeader("Setups", false);
using (new EditorGUILayout.HorizontalScope())
{
EditorGUI.BeginChangeCheck();
bool autoManage = EditorGUILayout.Toggle(
VRTK_EditorUtilities.BuildGUIContent<VRTK_SDKManager>("autoManageVRSettings"),
sdkManager.autoManageVRSettings,
GUILayout.ExpandWidth(false)
);
if (EditorGUI.EndChangeCheck())
{
serializedObject.FindProperty("autoManageVRSettings").boolValue = autoManage;
serializedObject.ApplyModifiedProperties();
sdkManager.ManageVRSettings(false);
}
using (new EditorGUI.DisabledGroupScope(sdkManager.autoManageVRSettings))
{
GUIContent manageNowGUIContent = new GUIContent(
manageNowButtonText,
"Manage the VR settings of the Player Settings to allow for all the installed SDKs."
+ (sdkManager.autoManageVRSettings
? "\n\nThis button is disabled because the SDK Manager is set up to manage the VR Settings automatically."
+ " Disable the checkbox on the left to allow managing them manually instead."
: "")
);
if (GUILayout.Button(manageNowGUIContent, GUILayout.MaxHeight(GUI.skin.label.CalcSize(manageNowGUIContent).y)))
{
sdkManager.ManageVRSettings(true);
}
}
}
EditorGUILayout.PropertyField(
serializedObject.FindProperty("autoLoadSetup"),
VRTK_EditorUtilities.BuildGUIContent<VRTK_SDKManager>("autoLoadSetup", "Auto Load")
);
setupsList.DoLayoutList();
GUIContent autoPopulateGUIContent = new GUIContent("Auto Populate", "Automatically populates the list of SDK Setups with Setups in the scene.");
if (GUILayout.Button(autoPopulateGUIContent))
{
SerializedProperty serializedProperty = setupsList.serializedProperty;
serializedProperty.ClearArray();
VRTK_SDKSetup[] setups = sdkManager.GetComponentsInChildren<VRTK_SDKSetup>(true)
.Concat(VRTK_SharedMethods.FindEvenInactiveComponents<VRTK_SDKSetup>(true))
.Distinct()
.ToArray();
for (int index = 0; index < setups.Length; index++)
{
VRTK_SDKSetup setup = setups[index];
serializedProperty.InsertArrayElementAtIndex(index);
serializedProperty.GetArrayElementAtIndex(index).objectReferenceValue = setup;
}
}
if (sdkManager.setups.Length > 1)
{
EditorGUILayout.HelpBox("Duplicated setups are removed automatically.", MessageType.Info);
}
if (Enumerable.Range(0, sdkManager.setups.Length).Any(IsSDKSetupNeverUsed))
{
EditorGUILayout.HelpBox("Gray setups will never be loaded because either the SDK Setup isn't valid or there"
+ " is a valid Setup before it that uses any non-VR SDK.",
MessageType.Warning);
}
}
using (new EditorGUILayout.VerticalScope("Box"))
{
VRTK_EditorUtilities.AddHeader("Target Platform Group Exclusions", false);
SerializedProperty excludeTargetGroups = serializedObject.FindProperty("excludeTargetGroups");
excludeTargetGroups.arraySize = EditorGUILayout.IntField("Size", excludeTargetGroups.arraySize);
for (int i = 0; i < excludeTargetGroups.arraySize; i++)
{
EditorGUILayout.PropertyField(excludeTargetGroups.GetArrayElementAtIndex(i));
}
}
EditorGUILayout.PropertyField(serializedObject.FindProperty("persistOnLoad"));
serializedObject.ApplyModifiedProperties();
}
private void UndoRedoPerformed()
{
VRTK_SDKManager sdkManager = (VRTK_SDKManager)target;
sdkManager.ManageVRSettings(false);
sdkManager.ManageScriptingDefineSymbols(false, false);
}
private bool IsSDKSetupNeverUsed(int sdkSetupIndex)
{
VRTK_SDKSetup[] setups = ((VRTK_SDKManager)target).setups;
VRTK_SDKSetup setup = setups[sdkSetupIndex];
return setup == null
|| !setup.isValid
|| Array.FindIndex(
setups,
0,
sdkSetupIndex,
sdkSetup => sdkSetup != null
&& sdkSetup.isValid
&& sdkSetup.usedVRDeviceNames.Contains("None")
) != -1;
}
}
}