No Description
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.

SpriteLibrary.cs 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. using System.Collections.Generic;
  2. using System.Linq;
  3. using UnityEngine.Scripting.APIUpdating;
  4. namespace UnityEngine.U2D.Animation
  5. {
  6. /// <summary>
  7. /// Component that holds a Sprite Library Asset. The component is used by SpriteResolver Component to query for Sprite based on Category and Index
  8. /// </summary>
  9. [DisallowMultipleComponent]
  10. [AddComponentMenu("2D Animation/Sprite Library")]
  11. [MovedFrom("UnityEngine.Experimental.U2D.Animation")]
  12. [HelpURL("https://docs.unity3d.com/Packages/com.unity.2d.animation@latest/index.html?subfolder=/manual/SLAsset.html%23sprite-library-component")]
  13. public class SpriteLibrary : MonoBehaviour
  14. {
  15. struct CategoryEntrySprite
  16. {
  17. public string category;
  18. public string entry;
  19. public Sprite sprite;
  20. }
  21. [SerializeField]
  22. List<SpriteLibCategory> m_Library = new List<SpriteLibCategory>();
  23. [SerializeField]
  24. SpriteLibraryAsset m_SpriteLibraryAsset;
  25. // Cache for combining data in sprite library asset and main library
  26. Dictionary<int, CategoryEntrySprite> m_CategoryEntryHashCache = null;
  27. Dictionary<string, HashSet<string>> m_CategoryEntryCache = null;
  28. int m_PreviousSpriteLibraryAsset;
  29. long m_PreviousModificationHash;
  30. /// <summary>Get or Set the current SpriteLibraryAsset to use </summary>
  31. public SpriteLibraryAsset spriteLibraryAsset
  32. {
  33. set
  34. {
  35. if (m_SpriteLibraryAsset != value)
  36. {
  37. m_SpriteLibraryAsset = value;
  38. CacheOverrides();
  39. RefreshSpriteResolvers();
  40. }
  41. }
  42. get { return m_SpriteLibraryAsset; }
  43. }
  44. void OnEnable()
  45. {
  46. CacheOverrides();
  47. }
  48. /// <summary>
  49. /// Return the Sprite that is registered for the given Category and Label for the SpriteLibrary
  50. /// </summary>
  51. /// <param name="category">Category name</param>
  52. /// <param name="label">Label name</param>
  53. /// <returns>Sprite associated to the name and index</returns>
  54. public Sprite GetSprite(string category, string label)
  55. {
  56. return GetSprite(GetHashForCategoryAndEntry(category, label));
  57. }
  58. Sprite GetSprite(int hash)
  59. {
  60. if (m_CategoryEntryHashCache.ContainsKey(hash))
  61. return m_CategoryEntryHashCache[hash].sprite;
  62. return null;
  63. }
  64. void UpdateCacheOverridesIfNeeded()
  65. {
  66. if(m_CategoryEntryCache == null ||
  67. m_PreviousSpriteLibraryAsset != m_SpriteLibraryAsset?.GetInstanceID() ||
  68. m_PreviousModificationHash != m_SpriteLibraryAsset?.modificationHash)
  69. CacheOverrides();
  70. }
  71. internal bool GetCategoryAndEntryNameFromHash(int hash, out string category, out string entry)
  72. {
  73. UpdateCacheOverridesIfNeeded();
  74. if (m_CategoryEntryHashCache.ContainsKey(hash))
  75. {
  76. category = m_CategoryEntryHashCache[hash].category;
  77. entry = m_CategoryEntryHashCache[hash].entry;
  78. return true;
  79. }
  80. category = null;
  81. entry = null;
  82. return false;
  83. }
  84. internal static int GetHashForCategoryAndEntry(string category, string entry)
  85. {
  86. return SpriteLibraryUtility.GetStringHash($"{category}_{entry}");
  87. }
  88. internal Sprite GetSpriteFromCategoryAndEntryHash(int hash, out bool validEntry)
  89. {
  90. UpdateCacheOverridesIfNeeded();
  91. if (m_CategoryEntryHashCache.ContainsKey(hash))
  92. {
  93. validEntry = true;
  94. return m_CategoryEntryHashCache[hash].sprite;
  95. }
  96. validEntry = false;
  97. return null;
  98. }
  99. List<SpriteCategoryEntry> GetEntries(string category, bool addIfNotExist)
  100. {
  101. var index = m_Library.FindIndex(x => x.name == category);
  102. if (index < 0)
  103. {
  104. if (!addIfNotExist)
  105. return null;
  106. m_Library.Add(new SpriteLibCategory()
  107. {
  108. name = category,
  109. categoryList = new List<SpriteCategoryEntry>()
  110. });
  111. index = m_Library.Count - 1;
  112. }
  113. return m_Library[index].categoryList;
  114. }
  115. SpriteCategoryEntry GetEntry(List<SpriteCategoryEntry> entries, string entry, bool addIfNotExist)
  116. {
  117. var index = entries.FindIndex(x => x.name == entry);
  118. if (index < 0)
  119. {
  120. if (!addIfNotExist)
  121. return null;
  122. entries.Add(new SpriteCategoryEntry()
  123. {
  124. name = entry,
  125. });
  126. index = entries.Count - 1;
  127. }
  128. return entries[index];
  129. }
  130. /// <summary>
  131. /// Add or replace an override when querying for the given Category and Label from a SpriteLibraryAsset
  132. /// </summary>
  133. /// <param name="spriteLib">Sprite Library Asset to query</param>
  134. /// <param name="category">Category name from the Sprite Library Asset to add override</param>
  135. /// <param name="label">Label name to add override</param>
  136. public void AddOverride(SpriteLibraryAsset spriteLib, string category, string label)
  137. {
  138. var sprite = spriteLib.GetSprite(category, label);
  139. var entries = GetEntries(category, true);
  140. var entry = GetEntry(entries, label, true);
  141. entry.sprite = sprite;
  142. CacheOverrides();
  143. }
  144. /// <summary>
  145. /// Add or replace an override when querying for the given Category. All the categories in the Category will be added.
  146. /// </summary>
  147. /// <param name="spriteLib">Sprite Library Asset to query</param>
  148. /// <param name="category">Category name from the Sprite Library Asset to add override</param>
  149. public void AddOverride(SpriteLibraryAsset spriteLib, string category)
  150. {
  151. var categoryHash = SpriteLibraryUtility.GetStringHash(category);
  152. var cat = spriteLib.categories.FirstOrDefault(x => x.hash == categoryHash);
  153. if (cat != null)
  154. {
  155. var entries = GetEntries(category, true);
  156. for (var i = 0; i < cat.categoryList.Count; ++i)
  157. {
  158. var ent = cat.categoryList[i];
  159. GetEntry(entries, ent.name, true).sprite = ent.sprite;
  160. }
  161. CacheOverrides();
  162. }
  163. }
  164. /// <summary>
  165. /// Add or replace an override when querying for the given Category and Label.
  166. /// </summary>
  167. /// <param name="sprite">Sprite to override to</param>
  168. /// <param name="category">Category name to override</param>
  169. /// <param name="label">Label name to override</param>
  170. public void AddOverride(Sprite sprite, string category, string label)
  171. {
  172. GetEntry(GetEntries(category, true), label, true).sprite = sprite;
  173. CacheOverrides();
  174. RefreshSpriteResolvers();
  175. }
  176. /// <summary>
  177. /// Remove all Sprite Library override for a given category
  178. /// </summary>
  179. /// <param name="category">Category overrides to remove</param>
  180. public void RemoveOverride(string category)
  181. {
  182. var index = m_Library.FindIndex(x => x.name == category);
  183. if (index >= 0)
  184. {
  185. m_Library.RemoveAt(index);
  186. CacheOverrides();
  187. RefreshSpriteResolvers();
  188. }
  189. }
  190. /// <summary>
  191. /// Remove Sprite Library override for a given category and label
  192. /// </summary>
  193. /// <param name="category">Category to remove</param>
  194. /// <param name="label">Label to remove</param>
  195. public void RemoveOverride(string category, string label)
  196. {
  197. var entries = GetEntries(category, false);
  198. if (entries != null)
  199. {
  200. var index = entries.FindIndex(x => x.name == label);
  201. if (index >= 0)
  202. {
  203. entries.RemoveAt(index);
  204. CacheOverrides();
  205. RefreshSpriteResolvers();
  206. }
  207. }
  208. }
  209. /// <summary>
  210. /// Method to check if a Category and Label pair has an override
  211. /// </summary>
  212. /// <param name="category">Category name</param>
  213. /// <param name="label">Label name</param>
  214. /// <returns>True if override exist, false otherwise</returns>
  215. public bool HasOverride(string category, string label)
  216. {
  217. var catOverride = GetEntries(category, false);
  218. if (catOverride != null)
  219. return GetEntry(catOverride, label, false) != null;
  220. return false;
  221. }
  222. /// <summary>
  223. /// Request SpriteResolver components that are in the same hierarchy to refresh
  224. /// </summary>
  225. public void RefreshSpriteResolvers()
  226. {
  227. var spriteResolvers = GetComponentsInChildren<SpriteResolver>();
  228. foreach (var sr in spriteResolvers)
  229. {
  230. sr.ResolveSpriteToSpriteRenderer();
  231. #if UNITY_EDITOR
  232. sr.spriteLibChanged = true;
  233. #endif
  234. }
  235. }
  236. internal IEnumerable<string> categoryNames
  237. {
  238. get
  239. {
  240. UpdateCacheOverridesIfNeeded();
  241. return m_CategoryEntryCache.Keys;
  242. }
  243. }
  244. internal IEnumerable<string> GetEntryNames(string category)
  245. {
  246. UpdateCacheOverridesIfNeeded();
  247. if (m_CategoryEntryCache.ContainsKey(category))
  248. return m_CategoryEntryCache[category];
  249. return null;
  250. }
  251. internal void CacheOverrides()
  252. {
  253. m_PreviousSpriteLibraryAsset = 0;
  254. m_PreviousModificationHash = 0;
  255. m_CategoryEntryHashCache = new Dictionary<int, CategoryEntrySprite>();
  256. m_CategoryEntryCache = new Dictionary<string, HashSet<string>>();
  257. if (m_SpriteLibraryAsset)
  258. {
  259. m_PreviousSpriteLibraryAsset = m_SpriteLibraryAsset.GetInstanceID();
  260. m_PreviousModificationHash = m_SpriteLibraryAsset.modificationHash;
  261. foreach (var category in m_SpriteLibraryAsset.categories)
  262. {
  263. var catName = category.name;
  264. m_CategoryEntryCache.Add(catName, new HashSet<string>());
  265. var cacheEntryName = m_CategoryEntryCache[catName];
  266. foreach (var entry in category.categoryList)
  267. {
  268. m_CategoryEntryHashCache.Add(GetHashForCategoryAndEntry(catName, entry.name), new CategoryEntrySprite()
  269. {
  270. category = catName,
  271. entry = entry.name,
  272. sprite = entry.sprite
  273. });
  274. cacheEntryName.Add(entry.name);
  275. }
  276. }
  277. }
  278. foreach (var category in m_Library)
  279. {
  280. var catName = category.name;
  281. if(!m_CategoryEntryCache.ContainsKey(catName))
  282. m_CategoryEntryCache.Add(catName, new HashSet<string>());
  283. var cacheEntryName = m_CategoryEntryCache[catName];
  284. foreach (var ent in category.categoryList)
  285. {
  286. if (!cacheEntryName.Contains(ent.name))
  287. cacheEntryName.Add(ent.name);
  288. var hash = GetHashForCategoryAndEntry(catName, ent.name);
  289. if (!m_CategoryEntryHashCache.ContainsKey(hash))
  290. {
  291. m_CategoryEntryHashCache.Add(hash, new CategoryEntrySprite()
  292. {
  293. category = catName,
  294. entry = ent.name,
  295. sprite = ent.sprite
  296. });
  297. }
  298. else
  299. {
  300. var e = m_CategoryEntryHashCache[hash];
  301. e.sprite = ent.sprite;
  302. m_CategoryEntryHashCache[hash] = e;
  303. }
  304. }
  305. }
  306. }
  307. }
  308. }