UMPSettingsEditor.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using UnityEditor;
  6. using UnityEngine;
  7. namespace UMP.Editor
  8. {
  9. [CustomEditor(typeof(UMPSettings))]
  10. [CanEditMultipleObjects]
  11. public class UMPSettingsEditor : UnityEditor.Editor
  12. {
  13. private const string VLC_VERSION = "3.0.6";
  14. private SerializedProperty _assetPathProp;
  15. private SerializedProperty _useAudioSourceProp;
  16. private SerializedProperty _useExternalLibrariesProp;
  17. private SerializedProperty _librariesPathProp;
  18. private SerializedProperty _youtubeDecryptFunctionProp;
  19. private static bool[] playersAndroid = null;
  20. private static bool[] playersIPhone = null;
  21. private static bool _showExportedPaths = false;
  22. private static int _exportedPathsSize;
  23. private static string[] _cachedExportedPaths;
  24. private static int _chosenMobilePlatform;
  25. private static GUIStyle _warningLabel = null;
  26. private static GUIStyle _buttonStyleToggled = null;
  27. private static Vector2 scrollPos;
  28. void OnEnable()
  29. {
  30. _assetPathProp = serializedObject.FindProperty("_assetPath");
  31. _useAudioSourceProp = serializedObject.FindProperty("_useAudioSource");
  32. _useExternalLibrariesProp = serializedObject.FindProperty("_useExternalLibraries");
  33. _librariesPathProp = serializedObject.FindProperty("_librariesPath");
  34. _youtubeDecryptFunctionProp = serializedObject.FindProperty("_youtubeDecryptFunction");
  35. }
  36. public override void OnInspectorGUI()
  37. {
  38. var settings = UMPSettings.Instance;
  39. var cachedLabelWidth = EditorGUIUtility.labelWidth;
  40. var installedMobilePlatforms = settings.GetInstalledPlatforms(UMPSettings.Mobile);
  41. if (_buttonStyleToggled == null)
  42. {
  43. _buttonStyleToggled = new GUIStyle(EditorStyles.miniButton);
  44. _buttonStyleToggled.normal.background = _buttonStyleToggled.active.background;
  45. }
  46. if (_warningLabel == null)
  47. {
  48. _warningLabel = new GUIStyle(EditorStyles.label);
  49. _warningLabel.padding = new RectOffset();
  50. _warningLabel.margin = new RectOffset();
  51. _warningLabel.wordWrap = true;
  52. }
  53. if (playersAndroid == null)
  54. {
  55. playersAndroid = new bool[Enum.GetNames(typeof(PlayerOptionsAndroid.PlayerTypes)).Length];
  56. for (int i = 0; i < playersAndroid.Length; i++)
  57. {
  58. var playerType = (PlayerOptionsAndroid.PlayerTypes)((i * 2) + (i == 0 ? 1 : 0));
  59. if ((settings.PlayersAndroid & playerType) == playerType)
  60. playersAndroid[i] = true;
  61. }
  62. }
  63. if (playersIPhone == null)
  64. {
  65. playersIPhone = new bool[Enum.GetNames(typeof(PlayerOptionsIPhone.PlayerTypes)).Length];
  66. for (int i = 0; i < playersIPhone.Length; i++)
  67. {
  68. var playerType = (PlayerOptionsIPhone.PlayerTypes)((i * 2) + (i == 0 ? 1 : 0));
  69. if ((settings.PlayersIPhone & playerType) == playerType)
  70. playersIPhone[i] = true;
  71. }
  72. }
  73. // Display the asset path
  74. #region Asset Path
  75. EditorGUILayout.BeginVertical(GUI.skin.box);
  76. EditorGUILayout.LabelField("Asset Path", EditorStyles.boldLabel);
  77. EditorGUI.BeginDisabledGroup(true);
  78. ShowMessageBox(MessageType.None, _assetPathProp.stringValue);
  79. EditorGUI.EndDisabledGroup();
  80. if (settings.IsValidAssetPath)
  81. ShowMessageBox(MessageType.Info, "Path is correct");
  82. else
  83. ShowMessageBox(MessageType.Error, "Can't find asset folder");
  84. GUI.color = Color.green;
  85. if (!settings.IsValidAssetPath)
  86. {
  87. if (GUILayout.Button("Find Asset Folder"))
  88. {
  89. GUI.FocusControl(null);
  90. _assetPathProp.stringValue = FindAssetFolder("Assets");
  91. }
  92. }
  93. GUI.color = Color.white;
  94. EditorGUILayout.EndVertical();
  95. #endregion
  96. // Display the Editor/Desktop options
  97. #region Editor/Desktop
  98. EditorGUILayout.BeginVertical(GUI.skin.box);
  99. EditorGUILayout.LabelField("Editor/Desktop", EditorStyles.boldLabel);
  100. EditorGUILayout.PropertyField(_useAudioSourceProp, new GUIContent("Use 'Audio Source'", "Will be using Unity 'Audio Source' component for audio output for all UMP instances (global) by default (supported only on desktop platforms)"));
  101. /*EditorGUILayout.BeginHorizontal();
  102. GUILayout.Label(new GUIContent("Use 'Audio Source' component", "Will be using Unity 'Audio Source' component for audio output for all UMP instances (global) by default."));
  103. _useAudioSourceProp.boolValue = EditorGUILayout.Toggle(_useAudioSourceProp.boolValue);
  104. EditorGUILayout.EndHorizontal();*/
  105. var useInstalled = !UMPSettings.ContainsLibVLC(settings.GetLibrariesPath(UMPSettings.RuntimePlatform, false));
  106. if (useInstalled)
  107. ShowMessageBox(MessageType.Warning, "Can't find internal LibVLC libraries in current project, so will be used installed VLC player software by default. To have possibility to use internal libraries please correctly import UMP (Win, Mac, Linux) package");
  108. if (_useExternalLibrariesProp.boolValue)
  109. EditorGUILayout.BeginVertical(GUI.skin.box);
  110. EditorGUILayout.PropertyField(_useExternalLibrariesProp, new GUIContent("Use installed VLC", "Use external/installed VLC player libraries for all UMP instances (global). Path to installed VLC player directory will be obtained automatically"));
  111. if (useInstalled)
  112. _useExternalLibrariesProp.boolValue = true;
  113. if (settings.UseExternalLibraries)
  114. {
  115. var librariesPath = settings.GetLibrariesPath(UMPSettings.RuntimePlatform, true);
  116. if (!UMPSettings.ContainsLibVLC(librariesPath))
  117. {
  118. librariesPath = string.Empty;
  119. GUI.color = Color.yellow;
  120. EditorGUILayout.BeginVertical(EditorStyles.textArea);
  121. EditorGUILayout.LabelField("Warning: Can't find installed VLC player software, please make sure that:\n" +
  122. "* Installed VLC player bit equals Unity Editor bit, eg., 'VLC Player 64 bit' == 'Unity Editor 64 bit'\n\n" +
  123. "* Use installer version from official site", _warningLabel);
  124. GUI.color = Color.white;
  125. var vlcUrl = string.Empty;
  126. switch (UMPSettings.RuntimePlatform)
  127. {
  128. case UMPSettings.Platforms.Win:
  129. vlcUrl = string.Format("http://get.videolan.org/vlc/{0}/win64/vlc-{0}-win64.exe", VLC_VERSION);
  130. if (UMPSettings.EditorBitMode == UMPSettings.BitModes.x86)
  131. vlcUrl = string.Format("http://get.videolan.org/vlc/{0}/win32/vlc-{0}-win32.exe", VLC_VERSION);
  132. break;
  133. case UMPSettings.Platforms.Mac:
  134. vlcUrl = string.Format("http://get.videolan.org/vlc/{0}/macosx/vlc-{0}.dmg", VLC_VERSION);
  135. break;
  136. }
  137. if (!string.IsNullOrEmpty(vlcUrl))
  138. {
  139. _warningLabel.normal.textColor = Color.blue;
  140. EditorGUILayout.LabelField(string.Format("{0} (Editor {1})", vlcUrl, UMPSettings.EditorBitModeFolderName), _warningLabel);
  141. _warningLabel.normal.textColor = Color.black;
  142. Rect urlRect = GUILayoutUtility.GetLastRect();
  143. if (Event.current.type == EventType.MouseUp && urlRect.Contains(Event.current.mousePosition))
  144. Application.OpenURL(vlcUrl);
  145. }
  146. EditorGUILayout.EndVertical();
  147. }
  148. EditorGUILayout.Space();
  149. EditorGUILayout.LabelField(new GUIContent("Libraries path", @"Path to installed VLC player libraries, eg., 'C:\Program Files\VideoLAN\VLC'"));
  150. if (!librariesPath.Equals(string.Empty))
  151. {
  152. _librariesPathProp.stringValue = librariesPath;
  153. EditorGUI.BeginDisabledGroup(true);
  154. ShowMessageBox(MessageType.None, _librariesPathProp.stringValue);
  155. EditorGUI.EndDisabledGroup();
  156. }
  157. else
  158. {
  159. ShowMessageBox(MessageType.Warning, "Path to installed VLC player directory can't be obtained automatically, try to use custom path to your libVLC libraries");
  160. _librariesPathProp.stringValue = EditorGUILayout.TextField(_librariesPathProp.stringValue);
  161. }
  162. if (UMPSettings.ContainsLibVLC(_librariesPathProp.stringValue))
  163. ShowMessageBox(MessageType.Info, "Path is correct");
  164. else
  165. ShowMessageBox(MessageType.Error, @"Can't find VLC player libraries, try to check if your path is correct, eg., 'C:\Program Files\VideoLAN\VLC'");
  166. }
  167. if (_useExternalLibrariesProp.boolValue)
  168. EditorGUILayout.EndVertical();
  169. EditorGUILayout.EndVertical();
  170. #endregion
  171. // Display the Mobile options
  172. #region Mobile
  173. EditorGUILayout.BeginVertical(GUI.skin.box);
  174. if (installedMobilePlatforms.Length > 0)
  175. {
  176. EditorGUILayout.LabelField("Mobile", EditorStyles.boldLabel);
  177. _chosenMobilePlatform = GUILayout.SelectionGrid(_chosenMobilePlatform, installedMobilePlatforms, installedMobilePlatforms.Length, EditorStyles.miniButton);
  178. EditorGUILayout.BeginVertical(GUI.skin.box);
  179. EditorGUILayout.LabelField(new GUIContent("Player Types", "Choose player types that will be used in your project"));
  180. ShowMessageBox(MessageType.Info, "Disabled players will be not included into your build (reducing the file size of your build)");
  181. GUILayout.BeginHorizontal();
  182. if (installedMobilePlatforms[_chosenMobilePlatform] == UMPSettings.Platforms.Android.ToString())
  183. {
  184. for (int i = 0; i < playersAndroid.Length; i++)
  185. {
  186. if (GUILayout.Button(Enum.GetName(typeof(PlayerOptionsAndroid.PlayerTypes), (i * 2) + (i == 0 ? 1 : 0)), playersAndroid[i] ? _buttonStyleToggled : EditorStyles.miniButton))
  187. {
  188. var playerType = (PlayerOptionsAndroid.PlayerTypes)((i * 2) + (i == 0 ? 1 : 0));
  189. if ((settings.PlayersAndroid & ~playerType) > 0)
  190. {
  191. playersAndroid[i] = !playersAndroid[i];
  192. settings.PlayersAndroid = playersAndroid[i] ? settings.PlayersAndroid | playerType : settings.PlayersAndroid & ~playerType;
  193. UpdateMobileLibraries(UMPSettings.Platforms.Android, settings.PlayersAndroid);
  194. }
  195. }
  196. }
  197. }
  198. if (installedMobilePlatforms[_chosenMobilePlatform] == UMPSettings.Platforms.iOS.ToString())
  199. {
  200. for (int i = 0; i < playersIPhone.Length; i++)
  201. {
  202. if (GUILayout.Button(Enum.GetName(typeof(PlayerOptionsIPhone.PlayerTypes), (i * 2) + (i == 0 ? 1 : 0)), playersIPhone[i] ? _buttonStyleToggled : EditorStyles.miniButton))
  203. {
  204. var playerType = (PlayerOptionsIPhone.PlayerTypes)((i * 2) + (i == 0 ? 1 : 0));
  205. if ((settings.PlayersIPhone & ~playerType) > 0)
  206. {
  207. playersIPhone[i] = !playersIPhone[i];
  208. settings.PlayersIPhone = playersIPhone[i] ? settings.PlayersIPhone | playerType : settings.PlayersIPhone & ~playerType;
  209. UpdateMobileLibraries(UMPSettings.Platforms.iOS, settings.PlayersIPhone);
  210. }
  211. }
  212. }
  213. }
  214. GUILayout.EndHorizontal();
  215. GUILayout.EndVertical();
  216. if (installedMobilePlatforms[_chosenMobilePlatform] == UMPSettings.Platforms.Android.ToString())
  217. {
  218. GUILayout.BeginVertical(GUI.skin.box);
  219. if (GUILayout.Button(new GUIContent("Exported Video Paths", "'StreamingAssets' videos (or video parts) that will be copied to special cached destination on device (for possibilities to use playlist: videos that contains many parts)"), _showExportedPaths ? _buttonStyleToggled : EditorStyles.miniButton))
  220. _showExportedPaths = !_showExportedPaths;
  221. if (_showExportedPaths)
  222. {
  223. scrollPos = EditorGUILayout.BeginScrollView(scrollPos, GUILayout.ExpandHeight(false));
  224. _exportedPathsSize = EditorGUILayout.IntField(new GUIContent("Size", "Amount of exported videos"), settings.AndroidExportedPaths.Length, GUILayout.ExpandWidth(true));
  225. if (_exportedPathsSize < 0)
  226. _exportedPathsSize = 0;
  227. _cachedExportedPaths = new string[_exportedPathsSize];
  228. if (_exportedPathsSize >= 0)
  229. {
  230. _cachedExportedPaths = new string[_exportedPathsSize];
  231. for (int i = 0; i < settings.AndroidExportedPaths.Length; i++)
  232. {
  233. if (i < _exportedPathsSize)
  234. _cachedExportedPaths[i] = settings.AndroidExportedPaths[i];
  235. }
  236. }
  237. EditorGUIUtility.labelWidth = 60;
  238. for (int i = 0; i < _cachedExportedPaths.Length; i++)
  239. _cachedExportedPaths[i] = EditorGUILayout.TextField("Path " + i + ":", _cachedExportedPaths[i]);
  240. EditorGUIUtility.labelWidth = cachedLabelWidth;
  241. settings.AndroidExportedPaths = _cachedExportedPaths;
  242. EditorGUILayout.EndScrollView();
  243. var evt = Event.current;
  244. switch (evt.type)
  245. {
  246. case EventType.DragUpdated:
  247. case EventType.DragPerform:
  248. DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
  249. if (evt.type == EventType.DragPerform)
  250. {
  251. DragAndDrop.AcceptDrag();
  252. var filePaths = DragAndDrop.paths;
  253. if (filePaths.Length > 0)
  254. {
  255. var arrayLength = settings.AndroidExportedPaths.Length > filePaths.Length ? settings.AndroidExportedPaths.Length : filePaths.Length;
  256. _cachedExportedPaths = new string[arrayLength];
  257. for (int i = 0; i < arrayLength; i++)
  258. {
  259. if (i < settings.AndroidExportedPaths.Length)
  260. _cachedExportedPaths[i] = settings.AndroidExportedPaths[i];
  261. if (i < filePaths.Length)
  262. _cachedExportedPaths[i] = filePaths[i];
  263. }
  264. settings.AndroidExportedPaths = _cachedExportedPaths;
  265. }
  266. }
  267. break;
  268. }
  269. }
  270. GUILayout.EndVertical();
  271. }
  272. }
  273. EditorGUILayout.EndVertical();
  274. #endregion
  275. // Display the Services options
  276. #region Services
  277. EditorGUILayout.BeginVertical(GUI.skin.box);
  278. EditorGUILayout.LabelField("Services", EditorStyles.boldLabel);
  279. EditorGUILayout.LabelField(new GUIContent("Youtube Decrypt Function", "Uses for decrypt the direct links to Youtube video"));
  280. _youtubeDecryptFunctionProp.stringValue = EditorGUILayout.TextField(_youtubeDecryptFunctionProp.stringValue);
  281. EditorGUILayout.EndVertical();
  282. #endregion
  283. serializedObject.ApplyModifiedProperties();
  284. }
  285. private static void ShowMessageBox(MessageType messageType, string message)
  286. {
  287. switch (messageType)
  288. {
  289. case MessageType.None:
  290. GUI.color = Color.white;
  291. break;
  292. case MessageType.Info:
  293. GUI.color = Color.green;
  294. message = "Info: " + message;
  295. break;
  296. case MessageType.Warning:
  297. GUI.color = Color.yellow;
  298. message = "Warning: " + message;
  299. break;
  300. case MessageType.Error:
  301. GUI.color = Color.red;
  302. message = "Error: " + message;
  303. break;
  304. }
  305. var textAreaStyle = EditorStyles.textArea;
  306. var wrap = textAreaStyle.wordWrap;
  307. textAreaStyle.wordWrap = true;
  308. EditorGUILayout.TextArea(message, textAreaStyle);
  309. textAreaStyle.wordWrap = wrap;
  310. GUI.color = Color.white;
  311. }
  312. private static string FindAssetFolder(string rootPath)
  313. {
  314. var projectFolders = Directory.GetDirectories(rootPath, "*", SearchOption.AllDirectories);
  315. foreach (var folderPath in projectFolders)
  316. {
  317. if (Path.GetFileName(folderPath).Contains(UMPSettings.ASSET_NAME) && Directory.GetFiles(folderPath).Length > 0)
  318. return folderPath.Replace(@"\", "/");
  319. }
  320. return string.Empty;
  321. }
  322. public static void UpdateMobileLibraries(UMPSettings.Platforms platform, Enum playerType)
  323. {
  324. if (!(playerType is PlayerOptionsAndroid.PlayerTypes) &&
  325. !(playerType is PlayerOptionsIPhone.PlayerTypes))
  326. throw new ArgumentException("Enum must be one of this enumerated type: 'PlayerOptionsAndroid.PlayerTypes' or 'PlayerOptionsAndroid.PlayerTypes'");
  327. var librariesPath = UMPSettings.Instance.GetLibrariesPath(platform, false);
  328. var playerValues = (int[])Enum.GetValues(playerType.GetType());
  329. var usedLibs = new List<string>();
  330. var flags = string.Empty;
  331. #if UNITY_2018_3_OR_NEWER
  332. flags = "-DBGRA32 ";
  333. #endif
  334. var addVLCLibs = false;
  335. if (playerType is PlayerOptionsAndroid.PlayerTypes)
  336. addVLCLibs = ((PlayerOptionsAndroid.PlayerTypes)playerType & PlayerOptionsAndroid.PlayerTypes.LibVLC) == PlayerOptionsAndroid.PlayerTypes.LibVLC;
  337. for (int i = 0; i < playerValues.Length; i++)
  338. {
  339. if (playerType is PlayerOptionsAndroid.PlayerTypes)
  340. {
  341. var type = (PlayerOptionsAndroid.PlayerTypes)playerValues[i];
  342. if (((PlayerOptionsAndroid.PlayerTypes)playerType & type) == type)
  343. {
  344. usedLibs.Add(type.ToString());
  345. }
  346. }
  347. if (playerType is PlayerOptionsIPhone.PlayerTypes)
  348. {
  349. var type = (PlayerOptionsIPhone.PlayerTypes)playerValues[i];
  350. if (((PlayerOptionsIPhone.PlayerTypes)playerType & type) == type)
  351. {
  352. usedLibs.Add(type.ToString());
  353. flags += "-D" + type.ToString().ToUpper() + " ";
  354. }
  355. }
  356. }
  357. var librariesFiles = new List<string>();
  358. librariesFiles.AddRange(Directory.GetFiles(librariesPath));
  359. librariesFiles.AddRange(Directory.GetDirectories(librariesPath));
  360. if (playerType is PlayerOptionsAndroid.PlayerTypes)
  361. {
  362. librariesFiles.AddRange(Directory.GetFiles(librariesPath + "libs/armeabi-v7a"));
  363. librariesFiles.AddRange(Directory.GetFiles(librariesPath + "libs/x86"));
  364. #if UNITY_2018_2_OR_NEWER
  365. librariesFiles.AddRange(Directory.GetFiles(librariesPath + "libs/arm64-v8a"));
  366. #endif
  367. }
  368. var assetFiles = librariesFiles.Select(x =>
  369. x.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar).
  370. Substring(x.LastIndexOf("Assets")));
  371. foreach (var assetFile in assetFiles)
  372. {
  373. var libraryName = Path.GetFileNameWithoutExtension(assetFile);
  374. var libraryImporter = AssetImporter.GetAtPath(assetFile) as PluginImporter;
  375. var isEnable = false;
  376. foreach (var name in usedLibs)
  377. {
  378. if (libraryName.Contains("Player" + name) ||
  379. libraryName.Contains("PlayerBase") ||
  380. libraryName.Contains("MediaPlayer") ||
  381. (addVLCLibs && libraryName.Contains("lib")))
  382. isEnable = true;
  383. }
  384. if (libraryImporter != null)
  385. {
  386. libraryImporter.SetCompatibleWithAnyPlatform(false);
  387. switch (platform)
  388. {
  389. case UMPSettings.Platforms.Android:
  390. libraryImporter.SetCompatibleWithPlatform(BuildTarget.Android, isEnable);
  391. var cpuType = string.Empty;
  392. if (assetFile.LastIndexOf("armeabi-v7a") > 0)
  393. cpuType = "ARMv7";
  394. else if (assetFile.LastIndexOf("x86") > 0)
  395. cpuType = "x86";
  396. else if (assetFile.LastIndexOf("arm64-v8a") > 0)
  397. cpuType = "ARM64";
  398. if (!string.IsNullOrEmpty(cpuType))
  399. libraryImporter.SetPlatformData(BuildTarget.Android, "CPU", cpuType);
  400. break;
  401. case UMPSettings.Platforms.iOS:
  402. libraryImporter.SetCompatibleWithPlatform(BuildTarget.iOS, isEnable);
  403. libraryImporter.SetPlatformData(BuildTarget.iOS, "CompileFlags", flags.Trim());
  404. break;
  405. }
  406. libraryImporter.SaveAndReimport();
  407. }
  408. }
  409. librariesFiles.Clear();
  410. }
  411. }
  412. }