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.

446 lines
22 KiB

  1. namespace VRTK
  2. {
  3. using UnityEngine;
  4. using UnityEditor;
  5. using UnityEditorInternal;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Linq;
  9. [CustomEditor(typeof(VRTK_SDKManager))]
  10. public class VRTK_SDKManagerEditor : Editor
  11. {
  12. private static readonly Dictionary<BuildTargetGroup, bool> isBuildTargetActiveSymbolsFoldOut;
  13. private ReorderableList setupsList;
  14. static VRTK_SDKManagerEditor()
  15. {
  16. BuildTargetGroup[] targetGroups = VRTK_SharedMethods.GetValidBuildTargetGroups();
  17. isBuildTargetActiveSymbolsFoldOut = new Dictionary<BuildTargetGroup, bool>(targetGroups.Length);
  18. foreach (BuildTargetGroup targetGroup in targetGroups)
  19. {
  20. isBuildTargetActiveSymbolsFoldOut[targetGroup] = true;
  21. }
  22. }
  23. protected virtual void OnEnable()
  24. {
  25. VRTK_SDKManager sdkManager = (VRTK_SDKManager)target;
  26. setupsList = new ReorderableList(serializedObject, serializedObject.FindProperty("setups"))
  27. {
  28. headerHeight = 2,
  29. drawElementCallback = (rect, index, active, focused) =>
  30. {
  31. SerializedProperty serializedProperty = setupsList.serializedProperty;
  32. if (serializedProperty.arraySize <= index)
  33. {
  34. return;
  35. }
  36. rect.y += 2;
  37. rect.height = EditorGUIUtility.singleLineHeight;
  38. Color previousColor = GUI.color;
  39. if (IsSDKSetupNeverUsed(index))
  40. {
  41. GUI.color = new Color(previousColor.r, previousColor.g, previousColor.b, 0.5f);
  42. }
  43. GUIContent unloadButtonGUIContent = new GUIContent("Unload", "Unload this SDK Setup.");
  44. GUIContent loadButtonGUIContent = new GUIContent("Load", "Try to load this SDK Setup.");
  45. float buttonGUIContentWidth = Mathf.Max(
  46. GUI.skin.button.CalcSize(unloadButtonGUIContent).x,
  47. GUI.skin.button.CalcSize(loadButtonGUIContent).x
  48. );
  49. VRTK_SDKSetup setup = (VRTK_SDKSetup)serializedProperty.GetArrayElementAtIndex(index).objectReferenceValue;
  50. if (EditorApplication.isPlaying && setup != null)
  51. {
  52. rect.width -= buttonGUIContentWidth + ReorderableList.Defaults.padding;
  53. }
  54. EditorGUI.BeginChangeCheck();
  55. EditorGUI.PropertyField(rect,
  56. serializedProperty.GetArrayElementAtIndex(index),
  57. GUIContent.none);
  58. if (EditorGUI.EndChangeCheck())
  59. {
  60. setup = (VRTK_SDKSetup)serializedProperty.GetArrayElementAtIndex(index).objectReferenceValue;
  61. if (setup != null)
  62. {
  63. int indexOfExistingDuplicateSetup = Enumerable
  64. .Range(0, serializedProperty.arraySize)
  65. .Except(new[] { index })
  66. .Where(i => (VRTK_SDKSetup)serializedProperty.GetArrayElementAtIndex(i).objectReferenceValue == setup)
  67. .DefaultIfEmpty(-1)
  68. .First();
  69. if (indexOfExistingDuplicateSetup != -1)
  70. {
  71. serializedProperty.GetArrayElementAtIndex(indexOfExistingDuplicateSetup).objectReferenceValue = null;
  72. setupsList.index = indexOfExistingDuplicateSetup;
  73. ReorderableList.defaultBehaviours.DoRemoveButton(setupsList);
  74. setupsList.index = index;
  75. }
  76. }
  77. sdkManager.ManageVRSettings(false);
  78. }
  79. GUI.color = previousColor;
  80. if (EditorApplication.isPlaying && setup != null)
  81. {
  82. rect.x += rect.width + ReorderableList.Defaults.padding;
  83. rect.width = buttonGUIContentWidth;
  84. if (sdkManager.loadedSetup == setup)
  85. {
  86. if (GUI.Button(rect, unloadButtonGUIContent))
  87. {
  88. sdkManager.UnloadSDKSetup();
  89. }
  90. }
  91. else
  92. {
  93. if (GUI.Button(rect, loadButtonGUIContent))
  94. {
  95. sdkManager.TryLoadSDKSetup(index, true, sdkManager.setups);
  96. }
  97. }
  98. }
  99. },
  100. onAddCallback = list =>
  101. {
  102. SerializedProperty serializedProperty = list.serializedProperty;
  103. int index = serializedProperty.arraySize;
  104. serializedProperty.arraySize++;
  105. list.index = index;
  106. SerializedProperty element = serializedProperty.GetArrayElementAtIndex(index);
  107. element.objectReferenceValue = null;
  108. sdkManager.ManageVRSettings(false);
  109. },
  110. onRemoveCallback = list =>
  111. {
  112. int index = list.index;
  113. VRTK_SDKSetup sdkSetup = sdkManager.setups[index];
  114. bool isLoaded = sdkManager.loadedSetup == sdkSetup;
  115. if (isLoaded)
  116. {
  117. sdkManager.UnloadSDKSetup();
  118. }
  119. if (sdkSetup != null)
  120. {
  121. list.serializedProperty.GetArrayElementAtIndex(index).objectReferenceValue = null;
  122. }
  123. ReorderableList.defaultBehaviours.DoRemoveButton(list);
  124. sdkManager.ManageVRSettings(false);
  125. },
  126. onReorderCallback = list => sdkManager.ManageVRSettings(false)
  127. };
  128. Undo.undoRedoPerformed += UndoRedoPerformed;
  129. }
  130. protected virtual void OnDisable()
  131. {
  132. Undo.undoRedoPerformed -= UndoRedoPerformed;
  133. setupsList = null;
  134. }
  135. public override void OnInspectorGUI()
  136. {
  137. serializedObject.Update();
  138. VRTK_SDKManager sdkManager = (VRTK_SDKManager)target;
  139. const string manageNowButtonText = "Manage Now";
  140. using (new EditorGUILayout.VerticalScope("Box"))
  141. {
  142. VRTK_EditorUtilities.AddHeader("Scripting Define Symbols", false);
  143. using (new EditorGUILayout.HorizontalScope())
  144. {
  145. EditorGUI.BeginChangeCheck();
  146. bool autoManage = EditorGUILayout.Toggle(
  147. VRTK_EditorUtilities.BuildGUIContent<VRTK_SDKManager>("autoManageScriptDefines", "Auto Manage"),
  148. sdkManager.autoManageScriptDefines,
  149. GUILayout.ExpandWidth(false)
  150. );
  151. if (EditorGUI.EndChangeCheck())
  152. {
  153. serializedObject.FindProperty("autoManageScriptDefines").boolValue = autoManage;
  154. serializedObject.ApplyModifiedProperties();
  155. sdkManager.ManageScriptingDefineSymbols(false, true);
  156. }
  157. using (new EditorGUI.DisabledGroupScope(sdkManager.autoManageScriptDefines))
  158. {
  159. GUIContent manageNowGUIContent = new GUIContent(
  160. manageNowButtonText,
  161. "Manage the scripting define symbols defined by the installed SDKs."
  162. + (sdkManager.autoManageScriptDefines
  163. ? "\n\nThis button is disabled because the SDK Manager is set up to manage the scripting define symbols automatically."
  164. + " Disable the checkbox on the left to allow managing them manually instead."
  165. : "")
  166. );
  167. if (GUILayout.Button(manageNowGUIContent, GUILayout.MaxHeight(GUI.skin.label.CalcSize(manageNowGUIContent).y)))
  168. {
  169. sdkManager.ManageScriptingDefineSymbols(true, true);
  170. }
  171. }
  172. }
  173. using (new EditorGUILayout.VerticalScope("Box"))
  174. {
  175. VRTK_EditorUtilities.AddHeader("Active Symbols Without SDK Classes", false);
  176. VRTK_SDKInfo[] availableSDKInfos = VRTK_SDKManager
  177. .AvailableSystemSDKInfos
  178. .Concat(VRTK_SDKManager.AvailableBoundariesSDKInfos)
  179. .Concat(VRTK_SDKManager.AvailableHeadsetSDKInfos)
  180. .Concat(VRTK_SDKManager.AvailableControllerSDKInfos)
  181. .ToArray();
  182. HashSet<string> sdkSymbols = new HashSet<string>(availableSDKInfos.Select(info => info.description.symbol));
  183. IGrouping<BuildTargetGroup, VRTK_SDKManager.ScriptingDefineSymbolPredicateInfo>[] availableGroupedPredicateInfos = VRTK_SDKManager
  184. .AvailableScriptingDefineSymbolPredicateInfos
  185. .GroupBy(info => info.attribute.buildTargetGroup)
  186. .ToArray();
  187. foreach (IGrouping<BuildTargetGroup, VRTK_SDKManager.ScriptingDefineSymbolPredicateInfo> grouping in availableGroupedPredicateInfos)
  188. {
  189. VRTK_SDKManager.ScriptingDefineSymbolPredicateInfo[] possibleActiveInfos = grouping
  190. .Where(info => !sdkSymbols.Contains(info.attribute.symbol)
  191. && grouping.Except(new[] { info })
  192. .All(predicateInfo => !(predicateInfo.methodInfo == info.methodInfo
  193. && sdkSymbols.Contains(predicateInfo.attribute.symbol))))
  194. .OrderBy(info => info.attribute.symbol)
  195. .ToArray();
  196. if (possibleActiveInfos.Length == 0)
  197. {
  198. continue;
  199. }
  200. EditorGUI.indentLevel++;
  201. BuildTargetGroup targetGroup = grouping.Key;
  202. isBuildTargetActiveSymbolsFoldOut[targetGroup] = EditorGUI.Foldout(
  203. EditorGUILayout.GetControlRect(),
  204. isBuildTargetActiveSymbolsFoldOut[targetGroup],
  205. targetGroup.ToString(),
  206. true
  207. );
  208. if (isBuildTargetActiveSymbolsFoldOut[targetGroup])
  209. {
  210. foreach (VRTK_SDKManager.ScriptingDefineSymbolPredicateInfo predicateInfo in possibleActiveInfos)
  211. {
  212. int symbolIndex = sdkManager
  213. .activeScriptingDefineSymbolsWithoutSDKClasses
  214. .FindIndex(attribute => attribute.symbol == predicateInfo.attribute.symbol);
  215. string symbolLabel = predicateInfo.attribute.symbol.Remove(
  216. 0,
  217. SDK_ScriptingDefineSymbolPredicateAttribute.RemovableSymbolPrefix.Length
  218. );
  219. if (!(bool)predicateInfo.methodInfo.Invoke(null, null))
  220. {
  221. symbolLabel += " (not installed)";
  222. }
  223. EditorGUI.BeginChangeCheck();
  224. bool isSymbolActive = EditorGUILayout.ToggleLeft(symbolLabel, symbolIndex != -1);
  225. if (EditorGUI.EndChangeCheck())
  226. {
  227. Undo.RecordObject(sdkManager, "Active Symbol Change");
  228. if (isSymbolActive)
  229. {
  230. sdkManager.activeScriptingDefineSymbolsWithoutSDKClasses.Add(predicateInfo.attribute);
  231. }
  232. else
  233. {
  234. sdkManager.activeScriptingDefineSymbolsWithoutSDKClasses.RemoveAt(symbolIndex);
  235. }
  236. sdkManager.ManageScriptingDefineSymbols(false, true);
  237. }
  238. }
  239. }
  240. EditorGUI.indentLevel--;
  241. }
  242. }
  243. VRTK_EditorUtilities.DrawUsingDestructiveStyle(GUI.skin.button, style =>
  244. {
  245. GUIContent clearSymbolsGUIContent = new GUIContent(
  246. "Remove All Symbols",
  247. "Remove all scripting define symbols of VRTK. This is handy if you removed the SDK files from your project but still have"
  248. + " the symbols defined which results in compile errors."
  249. + "\nIf you have the above checkbox enabled the symbols will be managed automatically after clearing them. Otherwise hit the"
  250. + " '" + manageNowButtonText + "' button to add the symbols for the currently installed SDKs again."
  251. );
  252. if (GUILayout.Button(clearSymbolsGUIContent, style))
  253. {
  254. BuildTargetGroup[] targetGroups = VRTK_SharedMethods.GetValidBuildTargetGroups();
  255. foreach (BuildTargetGroup targetGroup in targetGroups)
  256. {
  257. string[] currentSymbols = PlayerSettings.GetScriptingDefineSymbolsForGroup(targetGroup)
  258. .Split(';')
  259. .Distinct()
  260. .OrderBy(symbol => symbol, StringComparer.Ordinal)
  261. .ToArray();
  262. string[] newSymbols = currentSymbols
  263. .Where(symbol => !symbol.StartsWith(SDK_ScriptingDefineSymbolPredicateAttribute.RemovableSymbolPrefix, StringComparison.Ordinal))
  264. .ToArray();
  265. if (currentSymbols.SequenceEqual(newSymbols))
  266. {
  267. continue;
  268. }
  269. PlayerSettings.SetScriptingDefineSymbolsForGroup(targetGroup, string.Join(";", newSymbols));
  270. string[] removedSymbols = currentSymbols.Except(newSymbols).ToArray();
  271. if (removedSymbols.Length > 0)
  272. {
  273. VRTK_Logger.Info(VRTK_Logger.GetCommonMessage(VRTK_Logger.CommonMessageKeys.SCRIPTING_DEFINE_SYMBOLS_REMOVED, targetGroup, string.Join(", ", removedSymbols)));
  274. }
  275. }
  276. }
  277. });
  278. }
  279. using (new EditorGUILayout.VerticalScope("Box"))
  280. {
  281. VRTK_EditorUtilities.AddHeader("Script Aliases", false);
  282. EditorGUILayout.PropertyField(
  283. serializedObject.FindProperty("scriptAliasLeftController"),
  284. VRTK_EditorUtilities.BuildGUIContent<VRTK_SDKManager>("scriptAliasLeftController", "Left Controller")
  285. );
  286. EditorGUILayout.PropertyField(
  287. serializedObject.FindProperty("scriptAliasRightController"),
  288. VRTK_EditorUtilities.BuildGUIContent<VRTK_SDKManager>("scriptAliasRightController", "Right Controller")
  289. );
  290. }
  291. using (new EditorGUILayout.VerticalScope("Box"))
  292. {
  293. VRTK_EditorUtilities.AddHeader("Setups", false);
  294. using (new EditorGUILayout.HorizontalScope())
  295. {
  296. EditorGUI.BeginChangeCheck();
  297. bool autoManage = EditorGUILayout.Toggle(
  298. VRTK_EditorUtilities.BuildGUIContent<VRTK_SDKManager>("autoManageVRSettings"),
  299. sdkManager.autoManageVRSettings,
  300. GUILayout.ExpandWidth(false)
  301. );
  302. if (EditorGUI.EndChangeCheck())
  303. {
  304. serializedObject.FindProperty("autoManageVRSettings").boolValue = autoManage;
  305. serializedObject.ApplyModifiedProperties();
  306. sdkManager.ManageVRSettings(false);
  307. }
  308. using (new EditorGUI.DisabledGroupScope(sdkManager.autoManageVRSettings))
  309. {
  310. GUIContent manageNowGUIContent = new GUIContent(
  311. manageNowButtonText,
  312. "Manage the VR settings of the Player Settings to allow for all the installed SDKs."
  313. + (sdkManager.autoManageVRSettings
  314. ? "\n\nThis button is disabled because the SDK Manager is set up to manage the VR Settings automatically."
  315. + " Disable the checkbox on the left to allow managing them manually instead."
  316. : "")
  317. );
  318. if (GUILayout.Button(manageNowGUIContent, GUILayout.MaxHeight(GUI.skin.label.CalcSize(manageNowGUIContent).y)))
  319. {
  320. sdkManager.ManageVRSettings(true);
  321. }
  322. }
  323. }
  324. EditorGUILayout.PropertyField(
  325. serializedObject.FindProperty("autoLoadSetup"),
  326. VRTK_EditorUtilities.BuildGUIContent<VRTK_SDKManager>("autoLoadSetup", "Auto Load")
  327. );
  328. setupsList.DoLayoutList();
  329. GUIContent autoPopulateGUIContent = new GUIContent("Auto Populate", "Automatically populates the list of SDK Setups with Setups in the scene.");
  330. if (GUILayout.Button(autoPopulateGUIContent))
  331. {
  332. SerializedProperty serializedProperty = setupsList.serializedProperty;
  333. serializedProperty.ClearArray();
  334. VRTK_SDKSetup[] setups = sdkManager.GetComponentsInChildren<VRTK_SDKSetup>(true)
  335. .Concat(VRTK_SharedMethods.FindEvenInactiveComponents<VRTK_SDKSetup>(true))
  336. .Distinct()
  337. .ToArray();
  338. for (int index = 0; index < setups.Length; index++)
  339. {
  340. VRTK_SDKSetup setup = setups[index];
  341. serializedProperty.InsertArrayElementAtIndex(index);
  342. serializedProperty.GetArrayElementAtIndex(index).objectReferenceValue = setup;
  343. }
  344. }
  345. if (sdkManager.setups.Length > 1)
  346. {
  347. EditorGUILayout.HelpBox("Duplicated setups are removed automatically.", MessageType.Info);
  348. }
  349. if (Enumerable.Range(0, sdkManager.setups.Length).Any(IsSDKSetupNeverUsed))
  350. {
  351. EditorGUILayout.HelpBox("Gray setups will never be loaded because either the SDK Setup isn't valid or there"
  352. + " is a valid Setup before it that uses any non-VR SDK.",
  353. MessageType.Warning);
  354. }
  355. }
  356. using (new EditorGUILayout.VerticalScope("Box"))
  357. {
  358. VRTK_EditorUtilities.AddHeader("Target Platform Group Exclusions", false);
  359. SerializedProperty excludeTargetGroups = serializedObject.FindProperty("excludeTargetGroups");
  360. excludeTargetGroups.arraySize = EditorGUILayout.IntField("Size", excludeTargetGroups.arraySize);
  361. for (int i = 0; i < excludeTargetGroups.arraySize; i++)
  362. {
  363. EditorGUILayout.PropertyField(excludeTargetGroups.GetArrayElementAtIndex(i));
  364. }
  365. }
  366. EditorGUILayout.PropertyField(serializedObject.FindProperty("persistOnLoad"));
  367. serializedObject.ApplyModifiedProperties();
  368. }
  369. private void UndoRedoPerformed()
  370. {
  371. VRTK_SDKManager sdkManager = (VRTK_SDKManager)target;
  372. sdkManager.ManageVRSettings(false);
  373. sdkManager.ManageScriptingDefineSymbols(false, false);
  374. }
  375. private bool IsSDKSetupNeverUsed(int sdkSetupIndex)
  376. {
  377. VRTK_SDKSetup[] setups = ((VRTK_SDKManager)target).setups;
  378. VRTK_SDKSetup setup = setups[sdkSetupIndex];
  379. return setup == null
  380. || !setup.isValid
  381. || Array.FindIndex(
  382. setups,
  383. 0,
  384. sdkSetupIndex,
  385. sdkSetup => sdkSetup != null
  386. && sdkSetup.isValid
  387. && sdkSetup.usedVRDeviceNames.Contains("None")
  388. ) != -1;
  389. }
  390. }
  391. }