暂无描述
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

SpriteLibrarySourceAssetFactory.cs 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using UnityEngine;
  5. using UnityEngine.U2D.Animation;
  6. using Object = UnityEngine.Object;
  7. namespace UnityEditor.U2D.Animation
  8. {
  9. /// <summary>
  10. /// Represents a Sprite Library's label.
  11. /// </summary>
  12. [Serializable]
  13. public class SpriteLibraryLabel : ISpriteLibraryLabel
  14. {
  15. /// <summary>
  16. /// Label's name.
  17. /// </summary>
  18. public string name => m_Name;
  19. /// <summary>
  20. /// Sprite associated with the label.
  21. /// </summary>
  22. public Sprite sprite => m_Sprite;
  23. [SerializeField]
  24. string m_Name;
  25. [SerializeField]
  26. Sprite m_Sprite;
  27. /// <summary>
  28. /// Constructs a new label.
  29. /// </summary>
  30. /// <param name="labelName">Label's name.</param>
  31. /// <param name="labelSprite">Label's Sprite.</param>
  32. public SpriteLibraryLabel(string labelName, Sprite labelSprite)
  33. {
  34. m_Name = labelName;
  35. m_Sprite = labelSprite;
  36. }
  37. }
  38. /// <summary>
  39. /// Represents a Sprite Library's category.
  40. /// </summary>
  41. [Serializable]
  42. public class SpriteLibraryCategory : ISpriteLibraryCategory
  43. {
  44. /// <summary>
  45. /// Category's name.
  46. /// </summary>
  47. public string name => m_Name;
  48. /// <summary>
  49. /// List of labels in category.
  50. /// </summary>
  51. public IEnumerable<ISpriteLibraryLabel> labels => m_Labels;
  52. [SerializeField]
  53. List<SpriteLibraryLabel> m_Labels;
  54. [SerializeField]
  55. string m_Name;
  56. /// <summary>
  57. /// Constructs a new category.
  58. /// </summary>
  59. /// <param name="categoryName">Category's name.</param>
  60. /// <param name="categoryLabels">Collection of labels in a category.</param>
  61. public SpriteLibraryCategory(string categoryName, IEnumerable<SpriteLibraryLabel> categoryLabels)
  62. {
  63. m_Name = categoryName;
  64. m_Labels = new List<SpriteLibraryLabel>(categoryLabels);
  65. }
  66. }
  67. /// <summary>
  68. /// Class used for creating new Sprite Library Source Assets.
  69. /// </summary>
  70. public static class SpriteLibrarySourceAssetFactory
  71. {
  72. /// <summary>
  73. /// Sprite Library Source Asset's extension.
  74. /// </summary>
  75. public const string extension = SpriteLibrarySourceAsset.extension;
  76. /// <summary>
  77. /// Creates a new Sprite Library Source Asset at a given path.
  78. /// </summary>
  79. /// <param name="path">Save path. Must be within the Assets folder.</param>
  80. /// <param name="categories">Collection of categories in the library.</param>
  81. /// <param name="mainLibraryPath">A path to the main library. Null if there is no main library.</param>
  82. /// <returns>A relative path to the Project with correct extension.</returns>
  83. /// <exception cref="InvalidOperationException">Throws when the save path is invalid/</exception>
  84. public static string Create(string path, IEnumerable<ISpriteLibraryCategory> categories, string mainLibraryPath = null)
  85. {
  86. if (string.IsNullOrEmpty(path))
  87. throw new InvalidOperationException("Save path cannot be null or empty.");
  88. var relativePath = GetRelativePath(path);
  89. if (string.IsNullOrEmpty(relativePath))
  90. throw new InvalidOperationException($"{nameof(LoadSpriteLibrarySourceAsset)} can only be saved in the Assets folder.");
  91. relativePath = Path.ChangeExtension(relativePath, extension);
  92. SpriteLibraryAsset mainLibrary = null;
  93. if (!string.IsNullOrEmpty(mainLibraryPath))
  94. {
  95. mainLibrary = AssetDatabase.LoadAssetAtPath<SpriteLibraryAsset>(mainLibraryPath);
  96. if (mainLibrary == null)
  97. throw new InvalidOperationException($"No {nameof(SpriteLibraryAsset)} found at path: '{mainLibraryPath}'");
  98. }
  99. var asset = ScriptableObject.CreateInstance<SpriteLibrarySourceAsset>();
  100. var categoryList = new List<SpriteLibCategoryOverride>();
  101. if (categories != null)
  102. {
  103. foreach (var category in categories)
  104. {
  105. var spriteLibCategory = new SpriteLibCategoryOverride
  106. {
  107. name = category.name,
  108. overrideEntries = new List<SpriteCategoryEntryOverride>()
  109. };
  110. foreach (var label in category.labels)
  111. {
  112. var spriteCategoryEntryOverride = new SpriteCategoryEntryOverride
  113. {
  114. name = label.name,
  115. spriteOverride = label.sprite
  116. };
  117. spriteLibCategory.overrideEntries.Add(spriteCategoryEntryOverride);
  118. }
  119. categoryList.Add(spriteLibCategory);
  120. }
  121. }
  122. if (mainLibrary != null)
  123. {
  124. asset.SetPrimaryLibraryGUID(AssetDatabase.GUIDFromAssetPath(mainLibraryPath).ToString());
  125. var newCategories = mainLibrary.categories ?? new List<SpriteLibCategory>();
  126. var existingCategories = new List<SpriteLibCategoryOverride>(categoryList);
  127. categoryList.Clear();
  128. // populate new primary
  129. foreach (var newCategory in newCategories)
  130. {
  131. var labels = new List<SpriteCategoryEntryOverride>();
  132. SpriteLibCategoryOverride existingCategory = null;
  133. for (var i = 0; i < existingCategories.Count; i++)
  134. {
  135. var category = existingCategories[i];
  136. if (category.name == newCategory.name)
  137. {
  138. existingCategory = category;
  139. existingCategory.fromMain = true;
  140. existingCategories.RemoveAt(i);
  141. break;
  142. }
  143. }
  144. var newEntries = newCategory.categoryList;
  145. foreach (var newEntry in newEntries)
  146. {
  147. var sprite = newEntry.sprite;
  148. labels.Add(new SpriteCategoryEntryOverride
  149. {
  150. name = newEntry.name,
  151. sprite = sprite,
  152. spriteOverride = sprite,
  153. fromMain = true
  154. });
  155. }
  156. var overrideCount = 0;
  157. if (existingCategory != null)
  158. {
  159. foreach (var existingLabel in existingCategory.overrideEntries)
  160. {
  161. var foundLabel = false;
  162. foreach (var newLabel in labels)
  163. {
  164. if (existingLabel.name == newLabel.name)
  165. {
  166. if (newLabel.spriteOverride != existingLabel.spriteOverride)
  167. {
  168. newLabel.spriteOverride = existingLabel.spriteOverride;
  169. overrideCount++;
  170. }
  171. foundLabel = true;
  172. break;
  173. }
  174. }
  175. if (!foundLabel)
  176. {
  177. overrideCount++;
  178. labels.Add(new SpriteCategoryEntryOverride
  179. {
  180. name = existingLabel.name,
  181. sprite = existingLabel.sprite,
  182. spriteOverride = existingLabel.spriteOverride,
  183. fromMain = false
  184. });
  185. }
  186. }
  187. }
  188. categoryList.Add(new SpriteLibCategoryOverride
  189. {
  190. name = newCategory.name,
  191. overrideEntries = labels,
  192. fromMain = true,
  193. entryOverrideCount = overrideCount
  194. });
  195. }
  196. foreach (var existingCategory in existingCategories)
  197. {
  198. var keepCategory = false;
  199. if (existingCategory.fromMain)
  200. {
  201. for (var i = existingCategory.overrideEntries.Count; i-- > 0;)
  202. {
  203. var entry = existingCategory.overrideEntries[i];
  204. if (!entry.fromMain || entry.sprite != entry.spriteOverride)
  205. {
  206. entry.fromMain = false;
  207. entry.sprite = entry.spriteOverride;
  208. keepCategory = true;
  209. }
  210. else
  211. existingCategory.overrideEntries.RemoveAt(i);
  212. }
  213. }
  214. if (!existingCategory.fromMain || keepCategory)
  215. {
  216. existingCategory.fromMain = false;
  217. existingCategory.entryOverrideCount = 0;
  218. categoryList.Add(existingCategory);
  219. }
  220. }
  221. }
  222. asset.SetLibrary(categoryList);
  223. SpriteLibrarySourceAssetImporter.SaveSpriteLibrarySourceAsset(asset, relativePath);
  224. Object.DestroyImmediate(asset);
  225. return relativePath;
  226. }
  227. /// <summary>
  228. /// Creates a new Sprite Library Source Asset at a given path.
  229. /// </summary>
  230. /// <param name="path">Save path. Must be within the Assets folder.</param>
  231. /// <param name="spriteLibraryAsset">Sprite Library Asset to be saved.</param>
  232. /// <param name="mainLibraryPath">A path to the main library. Null if there is no main library.</param>
  233. /// <returns>A relative path to the Project with correct extension.</returns>
  234. /// <exception cref="InvalidOperationException">Throws when the save path is invalid/</exception>
  235. public static string Create(string path, SpriteLibraryAsset spriteLibraryAsset, string mainLibraryPath = null)
  236. {
  237. return Create(path, spriteLibraryAsset.categories, mainLibraryPath);
  238. }
  239. /// <summary>
  240. /// Creates a new Sprite Library Source Asset at a given path.
  241. /// </summary>
  242. /// <param name="spriteLibraryAsset">Sprite Library Asset to be saved.</param>
  243. /// <param name="path">Save path. Must be within the Assets folder.</param>
  244. /// <param name="mainLibraryPath">A path to the main library. Null if there is no main library.</param>
  245. /// <returns>A relative path to the Project with correct extension.</returns>
  246. /// <exception cref="InvalidOperationException">Throws when the save path is invalid/</exception>
  247. public static string SaveAsSourceAsset(this SpriteLibraryAsset spriteLibraryAsset, string path, string mainLibraryPath = null)
  248. {
  249. return Create(path, spriteLibraryAsset, mainLibraryPath);
  250. }
  251. internal static SpriteLibrarySourceAsset LoadSpriteLibrarySourceAsset(string path)
  252. {
  253. var loadedObjects = UnityEditorInternal.InternalEditorUtility.LoadSerializedFileAndForget(path);
  254. foreach (var obj in loadedObjects)
  255. {
  256. if (obj is SpriteLibrarySourceAsset asset)
  257. return asset;
  258. }
  259. return null;
  260. }
  261. static string GetRelativePath(string path)
  262. {
  263. if (string.IsNullOrWhiteSpace(path))
  264. return null;
  265. if (!path.StartsWith("Assets/") && !path.StartsWith(Application.dataPath))
  266. return null;
  267. var pathStartIndex = path.IndexOf("Assets");
  268. return pathStartIndex == -1 ? null : path.Substring(pathStartIndex);
  269. }
  270. }
  271. }