2021년 4학년 1학기 기업연계프로젝트2 컴퓨터소프트웨어공학과 <원광투어팀> 팀장 : 송유진 팀원 : 김나영, 이경희, 한유진
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.

624 lines
22 KiB

5 years ago
  1. //========= Copyright 2016-2020, HTC Corporation. All rights reserved. ===========
  2. using System;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Reflection;
  7. using HTC.UnityPlugin.Vive;
  8. using UnityEditor;
  9. using UnityEditor.Callbacks;
  10. using UnityEditorInternal.VR;
  11. using UnityEngine;
  12. using Assembly = System.Reflection.Assembly;
  13. #if UNITY_2018_1_OR_NEWER
  14. using UnityEditor.PackageManager;
  15. using PackageInfo = UnityEditor.PackageManager.PackageInfo;
  16. #endif
  17. #if UNITY_2017_3_OR_NEWER
  18. using UnityEditor.Compilation;
  19. #endif
  20. namespace HTC.UnityPlugin.VRModuleManagement
  21. {
  22. // This script manage define symbols used by VIU
  23. public class VRModuleManagerEditor : AssetPostprocessor
  24. #if UNITY_2017_1_OR_NEWER
  25. , UnityEditor.Build.IActiveBuildTargetChanged
  26. #endif
  27. {
  28. public class SymbolRequirement
  29. {
  30. public class ReqFieldInfo
  31. {
  32. public string typeName = string.Empty;
  33. public string name = string.Empty;
  34. public BindingFlags bindingAttr = BindingFlags.Default;
  35. }
  36. public class ReqMethodInfo
  37. {
  38. public string typeName = string.Empty;
  39. public string name = string.Empty;
  40. public BindingFlags bindingAttr;
  41. public string[] argTypeNames = null;
  42. public ParameterModifier[] argModifiers = null;
  43. }
  44. public string symbol = string.Empty;
  45. public string[] reqTypeNames = null;
  46. public string[] reqAnyTypeNames = null;
  47. public string[] reqFileNames = null;
  48. public string[] reqAnyFileNames = null;
  49. public ReqFieldInfo[] reqFields = null;
  50. public ReqFieldInfo[] reqAnyFields = null;
  51. public ReqMethodInfo[] reqMethods = null;
  52. public ReqMethodInfo[] reqAnyMethods = null;
  53. public Func<SymbolRequirement, bool> validateFunc = null;
  54. public static Dictionary<string, Type> s_foundTypes;
  55. public static void ResetFoundTypes()
  56. {
  57. if (s_foundTypes != null)
  58. {
  59. s_foundTypes.Clear();
  60. }
  61. }
  62. public void FindRequiredTypesInAssembly(Assembly assembly)
  63. {
  64. if (reqTypeNames != null)
  65. {
  66. foreach (var name in reqTypeNames)
  67. {
  68. TryAddTypeFromAssembly(name, assembly);
  69. }
  70. }
  71. if (reqAnyTypeNames != null)
  72. {
  73. foreach (var name in reqAnyTypeNames)
  74. {
  75. TryAddTypeFromAssembly(name, assembly);
  76. }
  77. }
  78. if (reqFields != null)
  79. {
  80. foreach (var field in reqFields)
  81. {
  82. TryAddTypeFromAssembly(field.typeName, assembly);
  83. }
  84. }
  85. if (reqAnyFields != null)
  86. {
  87. foreach (var field in reqAnyFields)
  88. {
  89. TryAddTypeFromAssembly(field.typeName, assembly);
  90. }
  91. }
  92. if (reqMethods != null)
  93. {
  94. foreach (var method in reqMethods)
  95. {
  96. TryAddTypeFromAssembly(method.typeName, assembly);
  97. if (method.argTypeNames != null)
  98. {
  99. foreach (var typeName in method.argTypeNames)
  100. {
  101. TryAddTypeFromAssembly(typeName, assembly);
  102. }
  103. }
  104. }
  105. }
  106. if (reqAnyMethods != null)
  107. {
  108. foreach (var method in reqAnyMethods)
  109. {
  110. TryAddTypeFromAssembly(method.typeName, assembly);
  111. if (method.argTypeNames != null)
  112. {
  113. foreach (var typeName in method.argTypeNames)
  114. {
  115. TryAddTypeFromAssembly(typeName, assembly);
  116. }
  117. }
  118. }
  119. }
  120. }
  121. private bool TryAddTypeFromAssembly(string name, Assembly assembly)
  122. {
  123. if (string.IsNullOrEmpty(name) || RequiredTypeFound(name)) { return false; }
  124. var type = assembly.GetType(name);
  125. if (type == null) { return false; }
  126. if (s_foundTypes == null) { s_foundTypes = new Dictionary<string, Type>(); }
  127. s_foundTypes.Add(name, type);
  128. return true;
  129. }
  130. private bool RequiredTypeFound(string name)
  131. {
  132. return s_foundTypes == null ? false : s_foundTypes.ContainsKey(name);
  133. }
  134. public bool Validate()
  135. {
  136. if (s_foundTypes == null) { return false; }
  137. if (reqTypeNames != null)
  138. {
  139. foreach (var name in reqTypeNames)
  140. {
  141. if (!s_foundTypes.ContainsKey(name)) { return false; }
  142. }
  143. }
  144. if (reqAnyTypeNames != null)
  145. {
  146. var found = false;
  147. foreach (var name in reqAnyTypeNames)
  148. {
  149. if (s_foundTypes.ContainsKey(name))
  150. {
  151. found = true;
  152. break;
  153. }
  154. }
  155. if (!found) { return false; }
  156. }
  157. if (reqFileNames != null)
  158. {
  159. foreach (var requiredFile in reqFileNames)
  160. {
  161. if (!DoesFileExist(requiredFile))
  162. {
  163. return false;
  164. }
  165. }
  166. }
  167. if (reqAnyFileNames != null)
  168. {
  169. var found = false;
  170. foreach (var requiredFile in reqAnyFileNames)
  171. {
  172. var files = Directory.GetFiles(Application.dataPath, requiredFile, SearchOption.AllDirectories);
  173. if (files != null && files.Length > 0)
  174. {
  175. found = true;
  176. break;
  177. }
  178. }
  179. if (!found) { return false; }
  180. }
  181. if (reqFields != null)
  182. {
  183. foreach (var field in reqFields)
  184. {
  185. Type type;
  186. if (!s_foundTypes.TryGetValue(field.typeName, out type)) { return false; }
  187. if (type.GetField(field.name, field.bindingAttr) == null) { return false; }
  188. }
  189. }
  190. if (reqAnyFields != null)
  191. {
  192. var found = false;
  193. foreach (var field in reqAnyFields)
  194. {
  195. Type type;
  196. if (!s_foundTypes.TryGetValue(field.typeName, out type)) { continue; }
  197. if (type.GetField(field.name, field.bindingAttr) == null) { continue; }
  198. found = true;
  199. break;
  200. }
  201. if (!found) { return false; }
  202. }
  203. if (reqMethods != null)
  204. {
  205. foreach (var method in reqMethods)
  206. {
  207. Type type;
  208. if (!s_foundTypes.TryGetValue(method.typeName, out type)) { return false; }
  209. var argTypes = new Type[method.argTypeNames == null ? 0 : method.argTypeNames.Length];
  210. for (int i = argTypes.Length - 1; i >= 0; --i)
  211. {
  212. if (!s_foundTypes.TryGetValue(method.argTypeNames[i], out argTypes[i])) { return false; }
  213. }
  214. if (type.GetMethod(method.name, method.bindingAttr, null, CallingConventions.Any, argTypes, method.argModifiers ?? new ParameterModifier[0]) == null) { return false; }
  215. }
  216. }
  217. if (reqAnyMethods != null)
  218. {
  219. var found = false;
  220. foreach (var method in reqAnyMethods)
  221. {
  222. Type type;
  223. if (!s_foundTypes.TryGetValue(method.typeName, out type)) { continue; }
  224. if (method.argTypeNames == null)
  225. {
  226. continue;
  227. }
  228. bool isAllArgTypesFound = true;
  229. var argTypes = new Type[method.argTypeNames.Length];
  230. for (int i = argTypes.Length - 1; i >= 0; --i)
  231. {
  232. if (!s_foundTypes.TryGetValue(method.argTypeNames[i], out argTypes[i]))
  233. {
  234. isAllArgTypesFound = false;
  235. break;
  236. }
  237. }
  238. if (!isAllArgTypesFound)
  239. {
  240. continue;
  241. }
  242. if (type.GetMethod(method.name, method.bindingAttr, null, CallingConventions.Any, argTypes, method.argModifiers ?? new ParameterModifier[0]) == null) { continue; }
  243. found = true;
  244. break;
  245. }
  246. if (!found) { return false; }
  247. }
  248. if (validateFunc != null)
  249. {
  250. if (!validateFunc(this)) { return false; }
  251. }
  252. return true;
  253. }
  254. }
  255. public abstract class SymbolRequirementCollection : List<SymbolRequirement> { }
  256. private static List<SymbolRequirement> s_symbolReqList;
  257. private static HashSet<string> s_referencedAssemblyNameSet;
  258. static VRModuleManagerEditor()
  259. {
  260. s_symbolReqList = new List<SymbolRequirement>();
  261. foreach (var type in Assembly.GetAssembly(typeof(SymbolRequirementCollection)).GetTypes().Where(t => t.IsClass && !t.IsAbstract && t.IsSubclassOf(typeof(SymbolRequirementCollection))))
  262. {
  263. s_symbolReqList.AddRange((SymbolRequirementCollection)Activator.CreateInstance(type));
  264. }
  265. s_symbolReqList.Add(new SymbolRequirement()
  266. {
  267. symbol = "VIU_PLUGIN",
  268. validateFunc = (req) => true,
  269. });
  270. s_symbolReqList.Add(new SymbolRequirement()
  271. {
  272. symbol = "VIU_PACKAGE",
  273. validateFunc = (req) => VIUSettingsEditor.PackageManagerHelper.IsPackageInList(VIUSettingsEditor.VIUPackageName),
  274. });
  275. s_symbolReqList.Add(new SymbolRequirement()
  276. {
  277. symbol = "VIU_SIUMULATOR_SUPPORT",
  278. validateFunc = (req) => Vive.VIUSettingsEditor.supportSimulator,
  279. });
  280. // Obsolete symbol, will be removed in all condition
  281. s_symbolReqList.Add(new SymbolRequirement()
  282. {
  283. symbol = "VIU_EXTERNAL_CAMERA_SWITCH",
  284. validateFunc = (req) => false,
  285. });
  286. // Obsolete symbol, will be removed in all condition
  287. s_symbolReqList.Add(new SymbolRequirement()
  288. {
  289. symbol = "VIU_BINDING_INTERFACE_SWITCH",
  290. validateFunc = (req) => false,
  291. });
  292. #if !UNITY_2017_1_OR_NEWER
  293. EditorUserBuildSettings.activeBuildTargetChanged += UpdateScriptingDefineSymbols;
  294. #endif
  295. }
  296. #if UNITY_2017_1_OR_NEWER
  297. public int callbackOrder { get { return 0; } }
  298. public void OnActiveBuildTargetChanged(BuildTarget previousTarget, BuildTarget newTarget)
  299. {
  300. UpdateScriptingDefineSymbols();
  301. }
  302. #endif
  303. [DidReloadScripts]
  304. public static void UpdateScriptingDefineSymbols()
  305. {
  306. if (!s_isUpdatingScriptingDefineSymbols)
  307. {
  308. s_isUpdatingScriptingDefineSymbols = true;
  309. EditorApplication.update += DoUpdateScriptingDefineSymbols;
  310. }
  311. }
  312. // From UnityEditor.AssetPostprocessor
  313. public static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
  314. {
  315. foreach (string assetPath in deletedAssets)
  316. {
  317. string deletedFileName = Path.GetFileName(assetPath);
  318. bool isFound = s_symbolReqList.Exists((req) =>
  319. {
  320. if (req == null || req.reqFileNames == null)
  321. {
  322. return false;
  323. }
  324. foreach (string fileName in req.reqFileNames)
  325. {
  326. if (fileName == deletedFileName)
  327. {
  328. return true;
  329. }
  330. }
  331. return false;
  332. });
  333. if (isFound)
  334. {
  335. if (!s_delayCallRemoveRegistered)
  336. {
  337. s_delayCallRemoveRegistered = true;
  338. EditorApplication.delayCall += RemoveAllVIUSymbols;
  339. }
  340. break;
  341. }
  342. }
  343. }
  344. private static bool s_isUpdatingScriptingDefineSymbols = false;
  345. private static void DoUpdateScriptingDefineSymbols()
  346. {
  347. if (EditorApplication.isPlaying) { EditorApplication.update -= DoUpdateScriptingDefineSymbols; return; }
  348. // some symbolRequirement depends on installed packages (only works when UNITY_2018_1_OR_NEWER)
  349. Vive.VIUSettingsEditor.PackageManagerHelper.PreparePackageList();
  350. if (Vive.VIUSettingsEditor.PackageManagerHelper.isPreparingList) { return; }
  351. foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
  352. {
  353. if (!IsReferenced(assembly))
  354. {
  355. continue;
  356. }
  357. try
  358. {
  359. foreach (var symbolReq in s_symbolReqList)
  360. {
  361. symbolReq.FindRequiredTypesInAssembly(assembly);
  362. }
  363. }
  364. catch (ReflectionTypeLoadException e)
  365. {
  366. Debug.LogWarning(e);
  367. Debug.LogWarning("load assembly " + assembly.FullName + " fail");
  368. }
  369. catch (Exception e)
  370. {
  371. Debug.LogError(e);
  372. }
  373. }
  374. var defineSymbols = GetDefineSymbols();
  375. var defineSymbolsChanged = false;
  376. foreach (var symbolReq in s_symbolReqList)
  377. {
  378. if (symbolReq.Validate())
  379. {
  380. if (!defineSymbols.Contains(symbolReq.symbol))
  381. {
  382. defineSymbols.Add(symbolReq.symbol);
  383. defineSymbolsChanged = true;
  384. }
  385. }
  386. else
  387. {
  388. if (defineSymbols.RemoveAll((symbol) => symbol == symbolReq.symbol) > 0)
  389. {
  390. defineSymbolsChanged = true;
  391. }
  392. }
  393. }
  394. if (defineSymbolsChanged)
  395. {
  396. SetDefineSymbols(defineSymbols);
  397. }
  398. SymbolRequirement.ResetFoundTypes();
  399. s_isUpdatingScriptingDefineSymbols = false;
  400. EditorApplication.update -= DoUpdateScriptingDefineSymbols;
  401. }
  402. private static bool s_delayCallRemoveRegistered;
  403. private static void RemoveAllVIUSymbols()
  404. {
  405. s_delayCallRemoveRegistered = false;
  406. EditorApplication.delayCall -= RemoveAllVIUSymbols;
  407. var defineSymbols = GetDefineSymbols();
  408. foreach (var symbolReq in s_symbolReqList)
  409. {
  410. defineSymbols.Remove(symbolReq.symbol);
  411. }
  412. SetDefineSymbols(defineSymbols);
  413. }
  414. private static List<string> GetDefineSymbols()
  415. {
  416. return new List<string>(PlayerSettings.GetScriptingDefineSymbolsForGroup(BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget)).Split(';'));
  417. }
  418. private static void SetDefineSymbols(List<string> symbols)
  419. {
  420. PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget), string.Join(";", symbols.ToArray()));
  421. }
  422. private static bool IsReferenced(Assembly assembly)
  423. {
  424. return GetReferencedAssemblyNameSet().Contains(assembly.GetName().Name);
  425. }
  426. private static HashSet<string> GetReferencedAssemblyNameSet()
  427. {
  428. if (s_referencedAssemblyNameSet != null)
  429. {
  430. return s_referencedAssemblyNameSet;
  431. }
  432. s_referencedAssemblyNameSet = new HashSet<string>();
  433. Assembly playerAssembly = typeof(VRModule).Assembly;
  434. Assembly editorAssembly = typeof(VRModuleManagerEditor).Assembly;
  435. // C# player referenced assemblies
  436. foreach (AssemblyName asmName in playerAssembly.GetReferencedAssemblies())
  437. {
  438. s_referencedAssemblyNameSet.Add(asmName.Name);
  439. }
  440. // C# editor referenced assemblies
  441. foreach (AssemblyName asmName in editorAssembly.GetReferencedAssemblies())
  442. {
  443. s_referencedAssemblyNameSet.Add(asmName.Name);
  444. }
  445. #if UNITY_2018_1_OR_NEWER
  446. // Unity player referenced assemblies
  447. UnityEditor.Compilation.Assembly playerUnityAsm = FindUnityAssembly(playerAssembly.GetName().Name, AssembliesType.Player);
  448. if (playerUnityAsm != null)
  449. {
  450. foreach (UnityEditor.Compilation.Assembly asm in playerUnityAsm.assemblyReferences)
  451. {
  452. s_referencedAssemblyNameSet.Add(asm.name);
  453. }
  454. }
  455. else
  456. {
  457. Debug.LogWarning("Player assembly not found.");
  458. }
  459. // Unity editor referenced assemblies
  460. UnityEditor.Compilation.Assembly editorUnityAsm = FindUnityAssembly(editorAssembly.GetName().Name, AssembliesType.Editor);
  461. if (editorUnityAsm != null)
  462. {
  463. foreach (UnityEditor.Compilation.Assembly asm in editorUnityAsm.assemblyReferences)
  464. {
  465. s_referencedAssemblyNameSet.Add(asm.name);
  466. }
  467. }
  468. else
  469. {
  470. Debug.LogWarning("Editor assembly not found.");
  471. }
  472. #elif UNITY_2017_3_OR_NEWER
  473. UnityEditor.Compilation.Assembly[] assemblies = CompilationPipeline.GetAssemblies();
  474. foreach (UnityEditor.Compilation.Assembly asm in assemblies)
  475. {
  476. s_referencedAssemblyNameSet.Add(asm.name);
  477. }
  478. #endif
  479. return s_referencedAssemblyNameSet;
  480. }
  481. #if UNITY_2018_1_OR_NEWER
  482. private static UnityEditor.Compilation.Assembly FindUnityAssembly(string name, AssembliesType type)
  483. {
  484. UnityEditor.Compilation.Assembly foundAssembly = null;
  485. UnityEditor.Compilation.Assembly[] assemblies = CompilationPipeline.GetAssemblies(type);
  486. foreach (UnityEditor.Compilation.Assembly asm in assemblies)
  487. {
  488. if (asm.name == name)
  489. {
  490. foundAssembly = asm;
  491. break;
  492. }
  493. }
  494. return foundAssembly;
  495. }
  496. #endif
  497. private static bool DoesFileExist(string fileName)
  498. {
  499. string[] fileNamesInAsset = Directory.GetFiles(Application.dataPath, fileName, SearchOption.AllDirectories);
  500. if (fileNamesInAsset != null && fileNamesInAsset.Length > 0)
  501. {
  502. return true;
  503. }
  504. #if UNITY_2018_1_OR_NEWER
  505. PackageCollection packages = VIUSettingsEditor.PackageManagerHelper.GetPackageList();
  506. foreach (UnityEditor.PackageManager.PackageInfo package in packages)
  507. {
  508. if (package == null)
  509. {
  510. continue;
  511. }
  512. if (package.source == PackageSource.BuiltIn)
  513. {
  514. continue;
  515. }
  516. var resolvedPath = package.resolvedPath.Trim();
  517. if (string.IsNullOrEmpty(resolvedPath))
  518. {
  519. continue;
  520. }
  521. string[] fileNamesInPackage = Directory.GetFiles(resolvedPath, fileName, SearchOption.AllDirectories);
  522. if (fileNamesInPackage != null && fileNamesInPackage.Length > 0)
  523. {
  524. return true;
  525. }
  526. }
  527. #endif
  528. return false;
  529. }
  530. }
  531. }