TextureLoadHelp.cs 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Linq;
  6. using UnityEngine;
  7. using UnityEngine.Networking;
  8. using UnityEngine.UI;
  9. public class TextureLoadHelp : MonoBehaviour
  10. {
  11. public static TextureLoadHelp _Instance;
  12. private Dictionary<string, TempTexData> tempTexList;
  13. private Dictionary<long, Material> waitLoadImgActionList;
  14. public float currentTotalSize = 0;
  15. public float maxSize = 200; //图片缓存-m
  16. private Dictionary<string, AssetBundle> loadDoneABList;
  17. private Dictionary<string, int> loadingABList;
  18. private void Awake()
  19. {
  20. _Instance = this;
  21. tempTexList = new Dictionary<string, TempTexData>();
  22. waitLoadImgActionList = new Dictionary<long, Material>();
  23. loadDoneABList = new Dictionary<string, AssetBundle>();
  24. loadingABList = new Dictionary<string, int>();
  25. }
  26. /// <summary>
  27. /// 加载图片
  28. /// </summary>
  29. /// <param name="path"></param>
  30. /// <param name="mat"></param>
  31. /// <returns></returns>
  32. public long LoadTexFromUrl(string path, Material mat)
  33. {
  34. long loadId = GetDownId();
  35. if (CheckCache(path))
  36. {
  37. mat.mainTexture=LoadFromCache(path);
  38. return 0;
  39. }
  40. if (tempTexList.TryGetValue(path, out var value))
  41. {
  42. value.isUsing = true;
  43. mat.mainTexture = value.tex;
  44. loadId = 0;
  45. }
  46. else
  47. {
  48. waitLoadImgActionList.Add(loadId, mat);
  49. StartCoroutine(DownLoadTex(path, loadId));
  50. }
  51. return loadId;
  52. }
  53. public long LoadTexFromUrl_AB(string ab_Name,string FileName, Material mat)
  54. {
  55. if (tempTexList.TryGetValue(FileName, out var value))
  56. {
  57. value.isUsing = true;
  58. mat.mainTexture = value.tex;
  59. return 0;
  60. }
  61. long loadId = GetDownId();
  62. waitLoadImgActionList.Add(loadId, mat);
  63. StartCoroutine(DownLoadTex_AB(ab_Name,FileName,loadId));
  64. return loadId;
  65. }
  66. /// <summary>
  67. /// 取消加载
  68. /// </summary>
  69. /// <param name="loadId"></param>
  70. public void CancelLoad(long loadId)
  71. {
  72. if (waitLoadImgActionList.ContainsKey(loadId))
  73. {
  74. waitLoadImgActionList.Remove(loadId);
  75. }
  76. }
  77. /// <summary>
  78. /// 标记缓存图片为未使用
  79. /// </summary>
  80. /// <param name="path"></param>
  81. public void UnUsingTex(string path)
  82. {
  83. if (tempTexList.TryGetValue(path, out TempTexData disposeData))
  84. {
  85. disposeData.isUsing = false;
  86. }
  87. else
  88. {
  89. Debug.Log($"不存在缓存:{path}");
  90. }
  91. }
  92. IEnumerator DownLoadTex_AB(string ab_Name,string fileName, long loadId)
  93. {
  94. if (loadingABList.ContainsKey(ab_Name))
  95. {
  96. Debug.Log($"{ab_Name} downloading...wait");
  97. yield return new WaitUntil(() => loadingABList[ab_Name] > 0);
  98. // if (loadingABList.ContainsKey(ab_Name))
  99. // {
  100. // loadingABList.Remove(ab_Name);
  101. // }
  102. }
  103. AssetBundle tempAb;
  104. Texture2D tex;
  105. if (loadDoneABList.TryGetValue(ab_Name, out var value))
  106. {
  107. tempAb = value;
  108. tex=tempAb.LoadAsset<Texture2D>(fileName);
  109. if (waitLoadImgActionList.TryGetValue(loadId, out Material targetMat))
  110. {
  111. if (targetMat != null)
  112. {
  113. targetMat.mainTexture = tex;
  114. }
  115. waitLoadImgActionList.Remove(loadId);
  116. }
  117. }
  118. else
  119. {
  120. //添加到正在下载
  121. loadingABList.TryAdd(ab_Name,0);
  122. WWW www = WWW.LoadFromCacheOrDownload($"{Application.streamingAssetsPath}/{ab_Name}",0);
  123. yield return www;
  124. if (www.isDone)
  125. {
  126. tempAb = www.assetBundle;
  127. loadDoneABList.Add(ab_Name,tempAb);
  128. loadingABList[ab_Name]=1;
  129. tex=tempAb.LoadAsset<Texture2D>(fileName);
  130. tempTexList.TryAdd(fileName, new TempTexData()
  131. {
  132. loadTime = GetTimeStamp(),
  133. name = fileName,
  134. tex = tex,
  135. size = 0,
  136. isUsing = true
  137. });
  138. if (waitLoadImgActionList.TryGetValue(loadId, out Material targetMat))
  139. {
  140. if (targetMat != null)
  141. {
  142. targetMat.mainTexture = tex;
  143. }
  144. waitLoadImgActionList.Remove(loadId);
  145. }
  146. }
  147. else
  148. {
  149. loadingABList[ab_Name]=2;
  150. Debug.LogError($"{ab_Name}下载失败:{www.error}");
  151. }
  152. www.Dispose();
  153. }
  154. }
  155. IEnumerator DownLoadTex(string path, long loadId)
  156. {
  157. UnityWebRequest www = UnityWebRequestTexture.GetTexture(path);
  158. yield return www.SendWebRequest();
  159. if (www.downloadHandler.isDone)
  160. {
  161. if (waitLoadImgActionList.ContainsKey(loadId))
  162. {
  163. var texture = ((DownloadHandlerTexture)www.downloadHandler).texture;
  164. float tempSize = GetSize_m(www.downloadedBytes);
  165. tempTexList.TryAdd(path, new TempTexData()
  166. {
  167. loadTime = GetTimeStamp(),
  168. name = path,
  169. tex = texture,
  170. size = tempSize,
  171. isUsing = true
  172. });
  173. currentTotalSize += tempSize;
  174. CheckSize();
  175. if (waitLoadImgActionList.TryGetValue(loadId, out Material targetMat))
  176. {
  177. if (targetMat != null)
  178. {
  179. targetMat.mainTexture = texture;
  180. }
  181. waitLoadImgActionList.Remove(loadId);
  182. }
  183. SaveInCache(path, www.downloadHandler.data);
  184. }
  185. else
  186. {
  187. www.disposeDownloadHandlerOnDispose = true;
  188. Debug.Log(path + " 下载已取消");
  189. }
  190. }
  191. else
  192. {
  193. Debug.LogError($"{path}下载失败:{www.downloadHandler.error}");
  194. }
  195. www.Dispose();
  196. }
  197. private void SaveInCache(string url,byte[] data)
  198. {
  199. string fileName = Path.GetFileName(url);
  200. string path = Application.persistentDataPath;
  201. File.WriteAllBytes(path+fileName,data);
  202. Debug.Log($"缓存:{path}{fileName}");
  203. }
  204. private Texture2D LoadFromCache(string url)
  205. {
  206. string fileName = Path.GetFileName(url);
  207. string path = Application.persistentDataPath;
  208. byte[] texBytes=File.ReadAllBytes(path+fileName);
  209. currentTotalSize += GetSize_m((ulong)texBytes.Length);
  210. Texture2D tempTex = new Texture2D(2,2);
  211. tempTex.LoadImage(texBytes);
  212. tempTex.Apply();
  213. return tempTex;
  214. }
  215. private bool CheckCache(string url)
  216. {
  217. string fileName = Path.GetFileName(url);
  218. string path = Application.persistentDataPath;
  219. //Debug.Log($"CaChe:{path}");
  220. return File.Exists(path + fileName);
  221. }
  222. public void CheckSize()
  223. {
  224. if (currentTotalSize >= maxSize)
  225. {
  226. List<TempTexData> values = tempTexList.Values.ToList();
  227. values.Sort();
  228. for (int i = 0; i < values.Count; i++)
  229. {
  230. if (!values[i].isUsing)
  231. {
  232. if (tempTexList.TryGetValue(values[i].name, out TempTexData disposeData))
  233. {
  234. disposeData.tex = null;
  235. currentTotalSize -= disposeData.size;
  236. tempTexList.Remove(disposeData.name);
  237. }
  238. }
  239. if (currentTotalSize < maxSize)
  240. {
  241. break;
  242. }
  243. }
  244. if (currentTotalSize >= maxSize)
  245. {
  246. Debug.Log($"临时图片已超过限制大小且无可释放项!!!:{currentTotalSize}/{maxSize}");
  247. }
  248. }
  249. }
  250. /// <summary>
  251. /// 清空全部缓存
  252. /// </summary>
  253. public void ClearAllTempTex()
  254. {
  255. List<TempTexData> values = tempTexList.Values.ToList();
  256. for (int i = 0; i < values.Count; i++)
  257. {
  258. if (tempTexList.TryGetValue(values[i].name, out TempTexData disposeData))
  259. {
  260. disposeData.tex = null;
  261. currentTotalSize -= disposeData.size;
  262. tempTexList.Remove(disposeData.name);
  263. }
  264. }
  265. waitLoadImgActionList.Clear();
  266. tempTexList.Clear();
  267. Resources.UnloadUnusedAssets();
  268. GC.Collect();
  269. }
  270. private long GetDownId()
  271. {
  272. long id = ((DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000000);
  273. while (waitLoadImgActionList.ContainsKey(id))
  274. {
  275. id++;
  276. }
  277. return id;
  278. }
  279. private long GetTimeStamp()
  280. {
  281. return (DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000000;
  282. }
  283. private float GetSize_m(ulong size_b)
  284. {
  285. return (size_b*1.0f / (1024.0f * 1024.0f));
  286. }
  287. }
  288. public class TempTexData : IComparable<TempTexData>
  289. {
  290. public string name;
  291. public Texture tex;
  292. public long loadTime;
  293. public float size;
  294. public bool isUsing = true;
  295. public int CompareTo(TempTexData other)
  296. {
  297. if (other.loadTime < loadTime)
  298. {
  299. return 1;
  300. }
  301. if (other.loadTime == loadTime)
  302. {
  303. return 0;
  304. }
  305. return -1;
  306. }
  307. }