ABModel.cs 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795
  1. using System;
  2. using UnityEngine;
  3. using UnityEditor;
  4. using UnityEngine.Assertions;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using UnityEditor.IMGUI.Controls;
  8. using AssetBundleBrowser.AssetBundleDataSource;
  9. namespace AssetBundleBrowser.AssetBundleModel
  10. {
  11. /// <summary>
  12. /// Static class holding model data for Asset Bundle Browser tool. Data in Model is read from DataSource, but is not pushed.
  13. ///
  14. /// If not using a custom DataSource, then the data comes from the AssetDatabase. If you wish to alter the data from code,
  15. /// you should just push changes to the AssetDatabase then tell the Model to Rebuild(). If needed, you can also loop over
  16. /// Update() until it returns true to force all sub-items to refresh.
  17. ///
  18. /// </summary>
  19. public static class Model
  20. {
  21. const string k_NewBundleBaseName = "newbundle";
  22. const string k_NewVariantBaseName = "newvariant";
  23. internal static /*const*/ Color k_LightGrey = Color.grey * 1.5f;
  24. private static ABDataSource s_DataSource;
  25. private static BundleFolderConcreteInfo s_RootLevelBundles = new BundleFolderConcreteInfo("", null);
  26. private static List<ABMoveData> s_MoveData = new List<ABMoveData>();
  27. private static List<BundleInfo> s_BundlesToUpdate = new List<BundleInfo>();
  28. private static Dictionary<string, AssetInfo> s_GlobalAssetList = new Dictionary<string, AssetInfo>();
  29. private static Dictionary<string, HashSet<string>> s_DependencyTracker = new Dictionary<string, HashSet<string>>();
  30. private static bool s_InErrorState = false;
  31. const string k_DefaultEmptyMessage = "Drag assets here or right-click to begin creating bundles.";
  32. const string k_ProblemEmptyMessage = "There was a problem parsing the list of bundles. See console.";
  33. private static string s_EmptyMessageString;
  34. static private Texture2D s_folderIcon = null;
  35. static private Texture2D s_bundleIcon = null;
  36. static private Texture2D s_sceneIcon = null;
  37. /// <summary>
  38. /// If using a custom source of asset bundles, you can implement your own ABDataSource and set it here as the active
  39. /// DataSource. This will allow you to use the Browser with data that you provide.
  40. ///
  41. /// If no custom DataSource is provided, then the Browser will create one that feeds off of and into the
  42. /// AssetDatabase.
  43. ///
  44. /// </summary>
  45. public static ABDataSource DataSource
  46. {
  47. get
  48. {
  49. if (s_DataSource == null)
  50. {
  51. s_DataSource = new AssetDatabaseABDataSource ();
  52. }
  53. return s_DataSource;
  54. }
  55. set { s_DataSource = value; }
  56. }
  57. /// <summary>
  58. /// Update will loop over bundles that need updating and update them. It will only update one bundle
  59. /// per frame and will continue on the same bundle next frame until that bundle is marked as doneUpdating.
  60. /// By default, this will cause a very slow collection of dependency data as it will only update one bundle per
  61. /// </summary>
  62. public static bool Update()
  63. {
  64. bool shouldRepaint = false;
  65. ExecuteAssetMove(false); //this should never do anything. just a safety check.
  66. //TODO - look into EditorApplication callback functions.
  67. int size = s_BundlesToUpdate.Count;
  68. if (size > 0)
  69. {
  70. s_BundlesToUpdate[size - 1].Update();
  71. s_BundlesToUpdate.RemoveAll(item => item.doneUpdating == true);
  72. if (s_BundlesToUpdate.Count == 0)
  73. {
  74. shouldRepaint = true;
  75. foreach(var bundle in s_RootLevelBundles.GetChildList())
  76. {
  77. bundle.RefreshDupeAssetWarning();
  78. }
  79. }
  80. }
  81. return shouldRepaint;
  82. }
  83. internal static void ForceReloadData(TreeView tree)
  84. {
  85. s_InErrorState = false;
  86. Rebuild();
  87. tree.Reload();
  88. bool doneUpdating = s_BundlesToUpdate.Count == 0;
  89. EditorUtility.DisplayProgressBar("Updating Bundles", "", 0);
  90. int fullBundleCount = s_BundlesToUpdate.Count;
  91. while (!doneUpdating && !s_InErrorState)
  92. {
  93. int currCount = s_BundlesToUpdate.Count;
  94. EditorUtility.DisplayProgressBar("Updating Bundles", s_BundlesToUpdate[currCount-1].displayName, (float)(fullBundleCount- currCount) / (float)fullBundleCount);
  95. doneUpdating = Update();
  96. }
  97. EditorUtility.ClearProgressBar();
  98. }
  99. /// <summary>
  100. /// Clears and rebuilds model data.
  101. /// </summary>
  102. public static void Rebuild()
  103. {
  104. s_RootLevelBundles = new BundleFolderConcreteInfo("", null);
  105. s_MoveData = new List<ABMoveData>();
  106. s_BundlesToUpdate = new List<BundleInfo>();
  107. s_GlobalAssetList = new Dictionary<string, AssetInfo>();
  108. Refresh();
  109. }
  110. internal static void AddBundlesToUpdate(IEnumerable<BundleInfo> bundles)
  111. {
  112. foreach(var bundle in bundles)
  113. {
  114. bundle.ForceNeedUpdate();
  115. s_BundlesToUpdate.Add(bundle);
  116. }
  117. }
  118. internal static void Refresh()
  119. {
  120. s_EmptyMessageString = k_ProblemEmptyMessage;
  121. if (s_InErrorState)
  122. return;
  123. var bundleList = ValidateBundleList();
  124. if(bundleList != null)
  125. {
  126. s_EmptyMessageString = k_DefaultEmptyMessage;
  127. foreach (var bundleName in bundleList)
  128. {
  129. AddBundleToModel(bundleName);
  130. }
  131. AddBundlesToUpdate(s_RootLevelBundles.GetChildList());
  132. }
  133. if(s_InErrorState)
  134. {
  135. s_RootLevelBundles = new BundleFolderConcreteInfo("", null);
  136. s_EmptyMessageString = k_ProblemEmptyMessage;
  137. }
  138. }
  139. internal static string[] ValidateBundleList()
  140. {
  141. var bundleList = DataSource.GetAllAssetBundleNames();
  142. bool valid = true;
  143. HashSet<string> bundleSet = new HashSet<string>();
  144. int index = 0;
  145. bool attemptedBundleReset = false;
  146. while(index < bundleList.Length)
  147. {
  148. var name = bundleList[index];
  149. if (!bundleSet.Add(name))
  150. {
  151. LogError("Two bundles share the same name: " + name);
  152. valid = false;
  153. }
  154. int lastDot = name.LastIndexOf('.');
  155. if (lastDot > -1)
  156. {
  157. var bunName = name.Substring(0, lastDot);
  158. var extraDot = bunName.LastIndexOf('.');
  159. if(extraDot > -1)
  160. {
  161. if(attemptedBundleReset)
  162. {
  163. var message = "Bundle name '" + bunName + "' contains a period.";
  164. message += " Internally Unity keeps 'bundleName' and 'variantName' separate, but externally treat them as 'bundleName.variantName'.";
  165. message += " If a bundleName contains a period, the build will (probably) succeed, but this tool cannot tell which portion is bundle and which portion is variant.";
  166. LogError(message);
  167. valid = false;
  168. }
  169. else
  170. {
  171. if (!DataSource.IsReadOnly ())
  172. {
  173. DataSource.RemoveUnusedAssetBundleNames();
  174. }
  175. index = 0;
  176. bundleSet.Clear();
  177. bundleList = DataSource.GetAllAssetBundleNames();
  178. attemptedBundleReset = true;
  179. continue;
  180. }
  181. }
  182. if (bundleList.Contains(bunName))
  183. {
  184. //there is a bundle.none and a bundle.variant coexisting. Need to fix that or return an error.
  185. if (attemptedBundleReset)
  186. {
  187. valid = false;
  188. var message = "Bundle name '" + bunName + "' exists without a variant as well as with variant '" + name.Substring(lastDot+1) + "'.";
  189. message += " That is an illegal state that will not build and must be cleaned up.";
  190. LogError(message);
  191. }
  192. else
  193. {
  194. if (!DataSource.IsReadOnly ())
  195. {
  196. DataSource.RemoveUnusedAssetBundleNames();
  197. }
  198. index = 0;
  199. bundleSet.Clear();
  200. bundleList = DataSource.GetAllAssetBundleNames();
  201. attemptedBundleReset = true;
  202. continue;
  203. }
  204. }
  205. }
  206. index++;
  207. }
  208. if (valid)
  209. return bundleList;
  210. else
  211. return null;
  212. }
  213. internal static bool BundleListIsEmpty()
  214. {
  215. return (s_RootLevelBundles.GetChildList().Count() == 0);
  216. }
  217. internal static string GetEmptyMessage()
  218. {
  219. return s_EmptyMessageString;
  220. }
  221. internal static BundleInfo CreateEmptyBundle(BundleFolderInfo folder = null, string newName = null)
  222. {
  223. if ((folder as BundleVariantFolderInfo) != null)
  224. return CreateEmptyVariant(folder as BundleVariantFolderInfo);
  225. folder = (folder == null) ? s_RootLevelBundles : folder;
  226. string name = GetUniqueName(folder, newName);
  227. BundleNameData nameData;
  228. nameData = new BundleNameData(folder.m_Name.bundleName, name);
  229. return AddBundleToFolder(folder, nameData);
  230. }
  231. internal static BundleInfo CreateEmptyVariant(BundleVariantFolderInfo folder)
  232. {
  233. string name = GetUniqueName(folder, k_NewVariantBaseName);
  234. string variantName = folder.m_Name.bundleName + "." + name;
  235. BundleNameData nameData = new BundleNameData(variantName);
  236. return AddBundleToFolder(folder.parent, nameData);
  237. }
  238. internal static BundleFolderInfo CreateEmptyBundleFolder(BundleFolderConcreteInfo folder = null)
  239. {
  240. folder = (folder == null) ? s_RootLevelBundles : folder;
  241. string name = GetUniqueName(folder) + "/dummy";
  242. BundleNameData nameData = new BundleNameData(folder.m_Name.bundleName, name);
  243. return AddFoldersToBundle(s_RootLevelBundles, nameData);
  244. }
  245. private static BundleInfo AddBundleToModel(string name)
  246. {
  247. if (name == null)
  248. return null;
  249. BundleNameData nameData = new BundleNameData(name);
  250. BundleFolderInfo folder = AddFoldersToBundle(s_RootLevelBundles, nameData);
  251. BundleInfo currInfo = AddBundleToFolder(folder, nameData);
  252. return currInfo;
  253. }
  254. private static BundleFolderConcreteInfo AddFoldersToBundle(BundleFolderInfo root, BundleNameData nameData)
  255. {
  256. BundleInfo currInfo = root;
  257. var folder = currInfo as BundleFolderConcreteInfo;
  258. var size = nameData.pathTokens.Count;
  259. for (var index = 0; index < size; index++)
  260. {
  261. if (folder != null)
  262. {
  263. currInfo = folder.GetChild(nameData.pathTokens[index]);
  264. if (currInfo == null)
  265. {
  266. currInfo = new BundleFolderConcreteInfo(nameData.pathTokens, index + 1, folder);
  267. folder.AddChild(currInfo);
  268. }
  269. folder = currInfo as BundleFolderConcreteInfo;
  270. if (folder == null)
  271. {
  272. s_InErrorState = true;
  273. LogFolderAndBundleNameConflict(currInfo.m_Name.fullNativeName);
  274. break;
  275. }
  276. }
  277. }
  278. return currInfo as BundleFolderConcreteInfo;
  279. }
  280. private static void LogFolderAndBundleNameConflict(string name)
  281. {
  282. var message = "Bundle '";
  283. message += name;
  284. message += "' has a name conflict with a bundle-folder.";
  285. message += "Display of bundle data and building of bundles will not work.";
  286. message += "\nDetails: If you name a bundle 'x/y', then the result of your build will be a bundle named 'y' in a folder named 'x'. You thus cannot also have a bundle named 'x' at the same level as the folder named 'x'.";
  287. LogError(message);
  288. }
  289. private static BundleInfo AddBundleToFolder(BundleFolderInfo root, BundleNameData nameData)
  290. {
  291. BundleInfo currInfo = root.GetChild(nameData.shortName);
  292. if (!System.String.IsNullOrEmpty(nameData.variant))
  293. {
  294. if(currInfo == null)
  295. {
  296. currInfo = new BundleVariantFolderInfo(nameData.bundleName, root);
  297. root.AddChild(currInfo);
  298. }
  299. var folder = currInfo as BundleVariantFolderInfo;
  300. if (folder == null)
  301. {
  302. var message = "Bundle named " + nameData.shortName;
  303. message += " exists both as a standard bundle, and a bundle with variants. ";
  304. message += "This message is not supported for display or actual bundle building. ";
  305. message += "You must manually fix bundle naming in the inspector.";
  306. LogError(message);
  307. return null;
  308. }
  309. currInfo = folder.GetChild(nameData.variant);
  310. if (currInfo == null)
  311. {
  312. currInfo = new BundleVariantDataInfo(nameData.fullNativeName, folder);
  313. folder.AddChild(currInfo);
  314. }
  315. }
  316. else
  317. {
  318. if (currInfo == null)
  319. {
  320. currInfo = new BundleDataInfo(nameData.fullNativeName, root);
  321. root.AddChild(currInfo);
  322. }
  323. else
  324. {
  325. var dataInfo = currInfo as BundleDataInfo;
  326. if (dataInfo == null)
  327. {
  328. s_InErrorState = true;
  329. LogFolderAndBundleNameConflict(nameData.fullNativeName);
  330. }
  331. }
  332. }
  333. return currInfo;
  334. }
  335. private static string GetUniqueName(BundleFolderInfo folder, string suggestedName = null)
  336. {
  337. suggestedName = (suggestedName == null) ? k_NewBundleBaseName : suggestedName;
  338. string name = suggestedName;
  339. int index = 1;
  340. bool foundExisting = (folder.GetChild(name) != null);
  341. while (foundExisting)
  342. {
  343. name = suggestedName + index;
  344. index++;
  345. foundExisting = (folder.GetChild(name) != null);
  346. }
  347. return name;
  348. }
  349. internal static BundleTreeItem CreateBundleTreeView()
  350. {
  351. return s_RootLevelBundles.CreateTreeView(-1);
  352. }
  353. internal static AssetTreeItem CreateAssetListTreeView(IEnumerable<AssetBundleModel.BundleInfo> selectedBundles)
  354. {
  355. var root = new AssetTreeItem();
  356. if (selectedBundles != null)
  357. {
  358. foreach (var bundle in selectedBundles)
  359. {
  360. bundle.AddAssetsToNode(root);
  361. }
  362. }
  363. return root;
  364. }
  365. internal static bool HandleBundleRename(BundleTreeItem item, string newName)
  366. {
  367. var originalName = new BundleNameData(item.bundle.m_Name.fullNativeName);
  368. var findDot = newName.LastIndexOf('.');
  369. var findSlash = newName.LastIndexOf('/');
  370. var findBSlash = newName.LastIndexOf('\\');
  371. if (findDot == 0 || findSlash == 0 || findBSlash == 0)
  372. return false; //can't start a bundle with a / or .
  373. bool result = item.bundle.HandleRename(newName, 0);
  374. if (findDot > 0 || findSlash > 0 || findBSlash > 0)
  375. {
  376. item.bundle.parent.HandleChildRename(newName, string.Empty);
  377. }
  378. ExecuteAssetMove();
  379. var node = FindBundle(originalName);
  380. if (node != null)
  381. {
  382. var message = "Failed to rename bundle named: ";
  383. message += originalName.fullNativeName;
  384. message += ". Most likely this is due to the bundle being assigned to a folder in your Assets directory, AND that folder is either empty or only contains assets that are explicitly assigned elsewhere.";
  385. Debug.LogError(message);
  386. }
  387. return result;
  388. }
  389. internal static void HandleBundleReparent(IEnumerable<BundleInfo> bundles, BundleFolderInfo parent)
  390. {
  391. parent = (parent == null) ? s_RootLevelBundles : parent;
  392. foreach (var bundle in bundles)
  393. {
  394. bundle.HandleReparent(parent.m_Name.bundleName, parent);
  395. }
  396. ExecuteAssetMove();
  397. }
  398. internal static void HandleBundleMerge(IEnumerable<BundleInfo> bundles, BundleDataInfo target)
  399. {
  400. foreach (var bundle in bundles)
  401. {
  402. bundle.HandleDelete(true, target.m_Name.bundleName, target.m_Name.variant);
  403. }
  404. ExecuteAssetMove();
  405. }
  406. internal static void HandleBundleDelete(IEnumerable<BundleInfo> bundles)
  407. {
  408. var nameList = new List<BundleNameData>();
  409. foreach (var bundle in bundles)
  410. {
  411. nameList.Add(bundle.m_Name);
  412. bundle.HandleDelete(true);
  413. }
  414. ExecuteAssetMove();
  415. //check to see if any bundles are still there...
  416. foreach(var name in nameList)
  417. {
  418. var node = FindBundle(name);
  419. if(node != null)
  420. {
  421. var message = "Failed to delete bundle named: ";
  422. message += name.fullNativeName;
  423. message += ". Most likely this is due to the bundle being assigned to a folder in your Assets directory, AND that folder is either empty or only contains assets that are explicitly assigned elsewhere.";
  424. Debug.LogError(message);
  425. }
  426. }
  427. }
  428. internal static BundleInfo FindBundle(BundleNameData name)
  429. {
  430. BundleInfo currNode = s_RootLevelBundles;
  431. foreach (var token in name.pathTokens)
  432. {
  433. if(currNode is BundleFolderInfo)
  434. {
  435. currNode = (currNode as BundleFolderInfo).GetChild(token);
  436. if (currNode == null)
  437. return null;
  438. }
  439. else
  440. {
  441. return null;
  442. }
  443. }
  444. if(currNode is BundleFolderInfo)
  445. {
  446. currNode = (currNode as BundleFolderInfo).GetChild(name.shortName);
  447. if(currNode is BundleVariantFolderInfo)
  448. {
  449. currNode = (currNode as BundleVariantFolderInfo).GetChild(name.variant);
  450. }
  451. return currNode;
  452. }
  453. else
  454. {
  455. return null;
  456. }
  457. }
  458. internal static BundleInfo HandleDedupeBundles(IEnumerable<BundleInfo> bundles, bool onlyOverlappedAssets)
  459. {
  460. var newBundle = CreateEmptyBundle();
  461. HashSet<string> dupeAssets = new HashSet<string>();
  462. HashSet<string> fullAssetList = new HashSet<string>();
  463. //if they were just selected, then they may still be updating.
  464. bool doneUpdating = s_BundlesToUpdate.Count == 0;
  465. while (!doneUpdating)
  466. doneUpdating = Update();
  467. foreach (var bundle in bundles)
  468. {
  469. foreach (var asset in bundle.GetDependencies())
  470. {
  471. if (onlyOverlappedAssets)
  472. {
  473. if (!fullAssetList.Add(asset.fullAssetName))
  474. dupeAssets.Add(asset.fullAssetName);
  475. }
  476. else
  477. {
  478. if (asset.IsMessageSet(MessageSystem.MessageFlag.AssetsDuplicatedInMultBundles))
  479. dupeAssets.Add(asset.fullAssetName);
  480. }
  481. }
  482. }
  483. if (dupeAssets.Count == 0)
  484. return null;
  485. MoveAssetToBundle(dupeAssets, newBundle.m_Name.bundleName, string.Empty);
  486. ExecuteAssetMove();
  487. return newBundle;
  488. }
  489. internal static BundleInfo HandleConvertToVariant(BundleDataInfo bundle)
  490. {
  491. bundle.HandleDelete(true, bundle.m_Name.bundleName, k_NewVariantBaseName);
  492. ExecuteAssetMove();
  493. var root = bundle.parent.GetChild(bundle.m_Name.shortName) as BundleVariantFolderInfo;
  494. if (root != null)
  495. return root.GetChild(k_NewVariantBaseName);
  496. else
  497. {
  498. //we got here because the converted bundle was empty.
  499. var vfolder = new BundleVariantFolderInfo(bundle.m_Name.bundleName, bundle.parent);
  500. var vdata = new BundleVariantDataInfo(bundle.m_Name.bundleName + "." + k_NewVariantBaseName, vfolder);
  501. bundle.parent.AddChild(vfolder);
  502. vfolder.AddChild(vdata);
  503. return vdata;
  504. }
  505. }
  506. internal class ABMoveData
  507. {
  508. internal string assetName;
  509. internal string bundleName;
  510. internal string variantName;
  511. internal ABMoveData(string asset, string bundle, string variant)
  512. {
  513. assetName = asset;
  514. bundleName = bundle;
  515. variantName = variant;
  516. }
  517. internal void Apply()
  518. {
  519. if (!DataSource.IsReadOnly ())
  520. {
  521. DataSource.SetAssetBundleNameAndVariant(assetName, bundleName, variantName);
  522. }
  523. }
  524. }
  525. internal static void MoveAssetToBundle(AssetInfo asset, string bundleName, string variant)
  526. {
  527. s_MoveData.Add(new ABMoveData(asset.fullAssetName, bundleName, variant));
  528. }
  529. internal static void MoveAssetToBundle(string assetName, string bundleName, string variant)
  530. {
  531. s_MoveData.Add(new ABMoveData(assetName, bundleName, variant));
  532. }
  533. internal static void MoveAssetToBundle(IEnumerable<AssetInfo> assets, string bundleName, string variant)
  534. {
  535. foreach (var asset in assets)
  536. MoveAssetToBundle(asset, bundleName, variant);
  537. }
  538. internal static void MoveAssetToBundle(IEnumerable<string> assetNames, string bundleName, string variant)
  539. {
  540. foreach (var assetName in assetNames)
  541. MoveAssetToBundle(assetName, bundleName, variant);
  542. }
  543. internal static void ExecuteAssetMove(bool forceAct=true)
  544. {
  545. var size = s_MoveData.Count;
  546. if(forceAct)
  547. {
  548. if (size > 0)
  549. {
  550. bool autoRefresh = EditorPrefs.GetBool("kAutoRefresh");
  551. EditorPrefs.SetBool("kAutoRefresh", false);
  552. EditorUtility.DisplayProgressBar("Moving assets to bundles", "", 0);
  553. for (int i = 0; i < size; i++)
  554. {
  555. EditorUtility.DisplayProgressBar("Moving assets to bundle " + s_MoveData[i].bundleName, System.IO.Path.GetFileNameWithoutExtension(s_MoveData[i].assetName), (float)i / (float)size);
  556. s_MoveData[i].Apply();
  557. }
  558. EditorUtility.ClearProgressBar();
  559. EditorPrefs.SetBool("kAutoRefresh", autoRefresh);
  560. s_MoveData.Clear();
  561. }
  562. if (!DataSource.IsReadOnly ())
  563. {
  564. DataSource.RemoveUnusedAssetBundleNames();
  565. }
  566. Refresh();
  567. }
  568. }
  569. //this version of CreateAsset is only used for dependent assets.
  570. internal static AssetInfo CreateAsset(string name, AssetInfo parent)
  571. {
  572. if (ValidateAsset(name))
  573. {
  574. var bundleName = GetBundleName(name);
  575. return CreateAsset(name, bundleName, parent);
  576. }
  577. return null;
  578. }
  579. internal static AssetInfo CreateAsset(string name, string bundleName)
  580. {
  581. if(ValidateAsset(name))
  582. {
  583. return CreateAsset(name, bundleName, null);
  584. }
  585. return null;
  586. }
  587. private static AssetInfo CreateAsset(string name, string bundleName, AssetInfo parent)
  588. {
  589. if(!System.String.IsNullOrEmpty(bundleName))
  590. {
  591. return new AssetInfo(name, bundleName);
  592. }
  593. else
  594. {
  595. AssetInfo info = null;
  596. if(!s_GlobalAssetList.TryGetValue(name, out info))
  597. {
  598. info = new AssetInfo(name, string.Empty);
  599. s_GlobalAssetList.Add(name, info);
  600. }
  601. info.AddParent(parent.displayName);
  602. return info;
  603. }
  604. }
  605. internal static bool ValidateAsset(string name)
  606. {
  607. if (!name.StartsWith("Assets/"))
  608. return false;
  609. string ext = System.IO.Path.GetExtension(name);
  610. if (ext == ".dll" || ext == ".cs" || ext == ".meta" || ext == ".js" || ext == ".boo")
  611. return false;
  612. return true;
  613. }
  614. internal static string GetBundleName(string asset)
  615. {
  616. return DataSource.GetAssetBundleName (asset);
  617. }
  618. internal static int RegisterAsset(AssetInfo asset, string bundle)
  619. {
  620. if(s_DependencyTracker.ContainsKey(asset.fullAssetName))
  621. {
  622. s_DependencyTracker[asset.fullAssetName].Add(bundle);
  623. int count = s_DependencyTracker[asset.fullAssetName].Count;
  624. if (count > 1)
  625. asset.SetMessageFlag(MessageSystem.MessageFlag.AssetsDuplicatedInMultBundles, true);
  626. return count;
  627. }
  628. var bundles = new HashSet<string>();
  629. bundles.Add(bundle);
  630. s_DependencyTracker.Add(asset.fullAssetName, bundles);
  631. return 1;
  632. }
  633. internal static void UnRegisterAsset(AssetInfo asset, string bundle)
  634. {
  635. if (s_DependencyTracker == null || asset == null)
  636. return;
  637. if (s_DependencyTracker.ContainsKey(asset.fullAssetName))
  638. {
  639. s_DependencyTracker[asset.fullAssetName].Remove(bundle);
  640. int count = s_DependencyTracker[asset.fullAssetName].Count;
  641. switch (count)
  642. {
  643. case 0:
  644. s_DependencyTracker.Remove(asset.fullAssetName);
  645. break;
  646. case 1:
  647. asset.SetMessageFlag(MessageSystem.MessageFlag.AssetsDuplicatedInMultBundles, false);
  648. break;
  649. default:
  650. break;
  651. }
  652. }
  653. }
  654. internal static IEnumerable<string> CheckDependencyTracker(AssetInfo asset)
  655. {
  656. if (s_DependencyTracker.ContainsKey(asset.fullAssetName))
  657. {
  658. return s_DependencyTracker[asset.fullAssetName];
  659. }
  660. return new HashSet<string>();
  661. }
  662. //TODO - switch local cache server on and utilize this method to stay up to date.
  663. //static List<string> m_importedAssets = new List<string>();
  664. //static List<string> m_deletedAssets = new List<string>();
  665. //static List<KeyValuePair<string, string>> m_movedAssets = new List<KeyValuePair<string, string>>();
  666. //class AssetBundleChangeListener : AssetPostprocessor
  667. //{
  668. // static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
  669. // {
  670. // m_importedAssets.AddRange(importedAssets);
  671. // m_deletedAssets.AddRange(deletedAssets);
  672. // for (int i = 0; i < movedAssets.Length; i++)
  673. // m_movedAssets.Add(new KeyValuePair<string, string>(movedFromAssetPaths[i], movedAssets[i]));
  674. // //m_dirty = true;
  675. // }
  676. //}
  677. static internal void LogError(string message)
  678. {
  679. Debug.LogError("AssetBundleBrowser: " + message);
  680. }
  681. static internal void LogWarning(string message)
  682. {
  683. Debug.LogWarning("AssetBundleBrowser: " + message);
  684. }
  685. static internal Texture2D GetFolderIcon()
  686. {
  687. if (s_folderIcon == null)
  688. FindBundleIcons();
  689. return s_folderIcon;
  690. }
  691. static internal Texture2D GetBundleIcon()
  692. {
  693. if (s_bundleIcon == null)
  694. FindBundleIcons();
  695. return s_bundleIcon;
  696. }
  697. static internal Texture2D GetSceneIcon()
  698. {
  699. if (s_sceneIcon == null)
  700. FindBundleIcons();
  701. return s_sceneIcon;
  702. }
  703. static private void FindBundleIcons()
  704. {
  705. s_folderIcon = EditorGUIUtility.FindTexture("Folder Icon");
  706. var packagePath = System.IO.Path.GetFullPath("Packages/com.unity.assetbundlebrowser");
  707. if (System.IO.Directory.Exists(packagePath))
  708. {
  709. s_bundleIcon = (Texture2D)AssetDatabase.LoadAssetAtPath("Packages/com.unity.assetbundlebrowser/Editor/Icons/ABundleBrowserIconY1756Basic.png", typeof(Texture2D));
  710. s_sceneIcon = (Texture2D)AssetDatabase.LoadAssetAtPath("Packages/com.unity.assetbundlebrowser/Editor/Icons/ABundleBrowserIconY1756Scene.png", typeof(Texture2D));
  711. }
  712. }
  713. }
  714. }