ResourceManager.ResourceLoader.LoadResourceAgent.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. //------------------------------------------------------------
  2. // Game Framework
  3. // Copyright © 2013-2021 loyalsoft. All rights reserved.
  4. // Homepage: http://www.game7000.com/
  5. // Feedback: http://www.game7000.com/
  6. //------------------------------------------------------------
  7. using GameFramework.FileSystem;
  8. using System;
  9. using System.Collections.Generic;
  10. using System.IO;
  11. namespace GameFramework.Resource
  12. {
  13. internal sealed partial class ResourceManager : GameFrameworkModule, IResourceManager
  14. {
  15. private sealed partial class ResourceLoader
  16. {
  17. /// <summary>
  18. /// 加载资源代理。
  19. /// </summary>
  20. private sealed partial class LoadResourceAgent : ITaskAgent<LoadResourceTaskBase>
  21. {
  22. private static readonly Dictionary<string, string> s_CachedResourceNames = new Dictionary<string, string>(StringComparer.Ordinal);
  23. private static readonly HashSet<string> s_LoadingAssetNames = new HashSet<string>(StringComparer.Ordinal);
  24. private static readonly HashSet<string> s_LoadingResourceNames = new HashSet<string>(StringComparer.Ordinal);
  25. private readonly ILoadResourceAgentHelper m_Helper;
  26. private readonly IResourceHelper m_ResourceHelper;
  27. private readonly ResourceLoader m_ResourceLoader;
  28. private readonly string m_ReadOnlyPath;
  29. private readonly string m_ReadWritePath;
  30. private readonly DecryptResourceCallback m_DecryptResourceCallback;
  31. private LoadResourceTaskBase m_Task;
  32. /// <summary>
  33. /// 初始化加载资源代理的新实例。
  34. /// </summary>
  35. /// <param name="loadResourceAgentHelper">加载资源代理辅助器。</param>
  36. /// <param name="resourceHelper">资源辅助器。</param>
  37. /// <param name="resourceLoader">加载资源器。</param>
  38. /// <param name="readOnlyPath">资源只读区路径。</param>
  39. /// <param name="readWritePath">资源读写区路径。</param>
  40. /// <param name="decryptResourceCallback">解密资源回调函数。</param>
  41. public LoadResourceAgent(ILoadResourceAgentHelper loadResourceAgentHelper, IResourceHelper resourceHelper, ResourceLoader resourceLoader, string readOnlyPath, string readWritePath, DecryptResourceCallback decryptResourceCallback)
  42. {
  43. if (loadResourceAgentHelper == null)
  44. {
  45. throw new GameFrameworkException("Load resource agent helper is invalid.");
  46. }
  47. if (resourceHelper == null)
  48. {
  49. throw new GameFrameworkException("Resource helper is invalid.");
  50. }
  51. if (resourceLoader == null)
  52. {
  53. throw new GameFrameworkException("Resource loader is invalid.");
  54. }
  55. if (decryptResourceCallback == null)
  56. {
  57. throw new GameFrameworkException("Decrypt resource callback is invalid.");
  58. }
  59. m_Helper = loadResourceAgentHelper;
  60. m_ResourceHelper = resourceHelper;
  61. m_ResourceLoader = resourceLoader;
  62. m_ReadOnlyPath = readOnlyPath;
  63. m_ReadWritePath = readWritePath;
  64. m_DecryptResourceCallback = decryptResourceCallback;
  65. m_Task = null;
  66. }
  67. public ILoadResourceAgentHelper Helper
  68. {
  69. get
  70. {
  71. return m_Helper;
  72. }
  73. }
  74. /// <summary>
  75. /// 获取加载资源任务。
  76. /// </summary>
  77. public LoadResourceTaskBase Task
  78. {
  79. get
  80. {
  81. return m_Task;
  82. }
  83. }
  84. /// <summary>
  85. /// 初始化加载资源代理。
  86. /// </summary>
  87. public void Initialize()
  88. {
  89. m_Helper.LoadResourceAgentHelperUpdate += OnLoadResourceAgentHelperUpdate;
  90. m_Helper.LoadResourceAgentHelperReadFileComplete += OnLoadResourceAgentHelperReadFileComplete;
  91. m_Helper.LoadResourceAgentHelperReadBytesComplete += OnLoadResourceAgentHelperReadBytesComplete;
  92. m_Helper.LoadResourceAgentHelperParseBytesComplete += OnLoadResourceAgentHelperParseBytesComplete;
  93. m_Helper.LoadResourceAgentHelperLoadComplete += OnLoadResourceAgentHelperLoadComplete;
  94. m_Helper.LoadResourceAgentHelperError += OnLoadResourceAgentHelperError;
  95. }
  96. /// <summary>
  97. /// 加载资源代理轮询。
  98. /// </summary>
  99. /// <param name="elapseSeconds">逻辑流逝时间,以秒为单位。</param>
  100. /// <param name="realElapseSeconds">真实流逝时间,以秒为单位。</param>
  101. public void Update(float elapseSeconds, float realElapseSeconds)
  102. {
  103. }
  104. /// <summary>
  105. /// 关闭并清理加载资源代理。
  106. /// </summary>
  107. public void Shutdown()
  108. {
  109. Reset();
  110. m_Helper.LoadResourceAgentHelperUpdate -= OnLoadResourceAgentHelperUpdate;
  111. m_Helper.LoadResourceAgentHelperReadFileComplete -= OnLoadResourceAgentHelperReadFileComplete;
  112. m_Helper.LoadResourceAgentHelperReadBytesComplete -= OnLoadResourceAgentHelperReadBytesComplete;
  113. m_Helper.LoadResourceAgentHelperParseBytesComplete -= OnLoadResourceAgentHelperParseBytesComplete;
  114. m_Helper.LoadResourceAgentHelperLoadComplete -= OnLoadResourceAgentHelperLoadComplete;
  115. m_Helper.LoadResourceAgentHelperError -= OnLoadResourceAgentHelperError;
  116. }
  117. public static void Clear()
  118. {
  119. s_CachedResourceNames.Clear();
  120. s_LoadingAssetNames.Clear();
  121. s_LoadingResourceNames.Clear();
  122. }
  123. /// <summary>
  124. /// 开始处理加载资源任务。
  125. /// </summary>
  126. /// <param name="task">要处理的加载资源任务。</param>
  127. /// <returns>开始处理任务的状态。</returns>
  128. public StartTaskStatus Start(LoadResourceTaskBase task)
  129. {
  130. if (task == null)
  131. {
  132. throw new GameFrameworkException("Task is invalid.");
  133. }
  134. m_Task = task;
  135. m_Task.StartTime = DateTime.UtcNow;
  136. ResourceInfo resourceInfo = m_Task.ResourceInfo;
  137. if (!resourceInfo.Ready)
  138. {
  139. m_Task.StartTime = default(DateTime);
  140. return StartTaskStatus.HasToWait;
  141. }
  142. if (IsAssetLoading(m_Task.AssetName))
  143. {
  144. m_Task.StartTime = default(DateTime);
  145. return StartTaskStatus.HasToWait;
  146. }
  147. if (!m_Task.IsScene)
  148. {
  149. AssetObject assetObject = m_ResourceLoader.m_AssetPool.Spawn(m_Task.AssetName);
  150. if (assetObject != null)
  151. {
  152. OnAssetObjectReady(assetObject);
  153. return StartTaskStatus.Done;
  154. }
  155. }
  156. foreach (string dependencyAssetName in m_Task.GetDependencyAssetNames())
  157. {
  158. if (!m_ResourceLoader.m_AssetPool.CanSpawn(dependencyAssetName))
  159. {
  160. m_Task.StartTime = default(DateTime);
  161. return StartTaskStatus.HasToWait;
  162. }
  163. }
  164. string resourceName = resourceInfo.ResourceName.Name;
  165. if (IsResourceLoading(resourceName))
  166. {
  167. m_Task.StartTime = default(DateTime);
  168. return StartTaskStatus.HasToWait;
  169. }
  170. s_LoadingAssetNames.Add(m_Task.AssetName);
  171. ResourceObject resourceObject = m_ResourceLoader.m_ResourcePool.Spawn(resourceName);
  172. if (resourceObject != null)
  173. {
  174. OnResourceObjectReady(resourceObject);
  175. return StartTaskStatus.CanResume;
  176. }
  177. s_LoadingResourceNames.Add(resourceName);
  178. string fullPath = null;
  179. if (!s_CachedResourceNames.TryGetValue(resourceName, out fullPath))
  180. {
  181. fullPath = Utility.Path.GetRegularPath(Path.Combine(resourceInfo.StorageInReadOnly ? m_ReadOnlyPath : m_ReadWritePath, resourceInfo.UseFileSystem ? resourceInfo.FileSystemName : resourceInfo.ResourceName.FullName));
  182. s_CachedResourceNames.Add(resourceName, fullPath);
  183. }
  184. if (resourceInfo.LoadType == LoadType.LoadFromFile)
  185. {
  186. if (resourceInfo.UseFileSystem)
  187. {
  188. IFileSystem fileSystem = m_ResourceLoader.m_ResourceManager.GetFileSystem(resourceInfo.FileSystemName, resourceInfo.StorageInReadOnly);
  189. m_Helper.ReadFile(fileSystem, resourceInfo.ResourceName.FullName);
  190. }
  191. else
  192. {
  193. m_Helper.ReadFile(fullPath);
  194. }
  195. }
  196. else if (resourceInfo.LoadType == LoadType.LoadFromMemory || resourceInfo.LoadType == LoadType.LoadFromMemoryAndQuickDecrypt || resourceInfo.LoadType == LoadType.LoadFromMemoryAndDecrypt)
  197. {
  198. if (resourceInfo.UseFileSystem)
  199. {
  200. IFileSystem fileSystem = m_ResourceLoader.m_ResourceManager.GetFileSystem(resourceInfo.FileSystemName, resourceInfo.StorageInReadOnly);
  201. m_Helper.ReadBytes(fileSystem, resourceInfo.ResourceName.FullName);
  202. }
  203. else
  204. {
  205. m_Helper.ReadBytes(fullPath);
  206. }
  207. }
  208. else
  209. {
  210. throw new GameFrameworkException(Utility.Text.Format("Resource load type '{0}' is not supported.", resourceInfo.LoadType));
  211. }
  212. return StartTaskStatus.CanResume;
  213. }
  214. /// <summary>
  215. /// 重置加载资源代理。
  216. /// </summary>
  217. public void Reset()
  218. {
  219. m_Helper.Reset();
  220. m_Task = null;
  221. }
  222. private static bool IsAssetLoading(string assetName)
  223. {
  224. return s_LoadingAssetNames.Contains(assetName);
  225. }
  226. private static bool IsResourceLoading(string resourceName)
  227. {
  228. return s_LoadingResourceNames.Contains(resourceName);
  229. }
  230. private void OnAssetObjectReady(AssetObject assetObject)
  231. {
  232. m_Helper.Reset();
  233. object asset = assetObject.Target;
  234. if (m_Task.IsScene)
  235. {
  236. m_ResourceLoader.m_SceneToAssetMap.Add(m_Task.AssetName, asset);
  237. }
  238. m_Task.OnLoadAssetSuccess(this, asset, (float)(DateTime.UtcNow - m_Task.StartTime).TotalSeconds);
  239. m_Task.Done = true;
  240. }
  241. private void OnResourceObjectReady(ResourceObject resourceObject)
  242. {
  243. m_Task.LoadMain(this, resourceObject);
  244. }
  245. private void OnError(LoadResourceStatus status, string errorMessage)
  246. {
  247. m_Helper.Reset();
  248. m_Task.OnLoadAssetFailure(this, status, errorMessage);
  249. s_LoadingAssetNames.Remove(m_Task.AssetName);
  250. s_LoadingResourceNames.Remove(m_Task.ResourceInfo.ResourceName.Name);
  251. m_Task.Done = true;
  252. }
  253. private void OnLoadResourceAgentHelperUpdate(object sender, LoadResourceAgentHelperUpdateEventArgs e)
  254. {
  255. m_Task.OnLoadAssetUpdate(this, e.Type, e.Progress);
  256. }
  257. private void OnLoadResourceAgentHelperReadFileComplete(object sender, LoadResourceAgentHelperReadFileCompleteEventArgs e)
  258. {
  259. ResourceObject resourceObject = ResourceObject.Create(m_Task.ResourceInfo.ResourceName.Name, e.Resource, m_ResourceHelper, m_ResourceLoader);
  260. m_ResourceLoader.m_ResourcePool.Register(resourceObject, true);
  261. s_LoadingResourceNames.Remove(m_Task.ResourceInfo.ResourceName.Name);
  262. OnResourceObjectReady(resourceObject);
  263. }
  264. private void OnLoadResourceAgentHelperReadBytesComplete(object sender, LoadResourceAgentHelperReadBytesCompleteEventArgs e)
  265. {
  266. byte[] bytes = e.GetBytes();
  267. ResourceInfo resourceInfo = m_Task.ResourceInfo;
  268. if (resourceInfo.LoadType == LoadType.LoadFromMemoryAndQuickDecrypt || resourceInfo.LoadType == LoadType.LoadFromMemoryAndDecrypt)
  269. {
  270. m_DecryptResourceCallback(bytes, 0, bytes.Length, resourceInfo.ResourceName.Name, resourceInfo.ResourceName.Variant, resourceInfo.ResourceName.Extension, resourceInfo.StorageInReadOnly, resourceInfo.FileSystemName, (byte)resourceInfo.LoadType, resourceInfo.Length, resourceInfo.HashCode);
  271. }
  272. m_Helper.ParseBytes(bytes);
  273. }
  274. private void OnLoadResourceAgentHelperParseBytesComplete(object sender, LoadResourceAgentHelperParseBytesCompleteEventArgs e)
  275. {
  276. ResourceObject resourceObject = ResourceObject.Create(m_Task.ResourceInfo.ResourceName.Name, e.Resource, m_ResourceHelper, m_ResourceLoader);
  277. m_ResourceLoader.m_ResourcePool.Register(resourceObject, true);
  278. s_LoadingResourceNames.Remove(m_Task.ResourceInfo.ResourceName.Name);
  279. OnResourceObjectReady(resourceObject);
  280. }
  281. private void OnLoadResourceAgentHelperLoadComplete(object sender, LoadResourceAgentHelperLoadCompleteEventArgs e)
  282. {
  283. AssetObject assetObject = null;
  284. if (m_Task.IsScene)
  285. {
  286. assetObject = m_ResourceLoader.m_AssetPool.Spawn(m_Task.AssetName);
  287. }
  288. if (assetObject == null)
  289. {
  290. List<object> dependencyAssets = m_Task.GetDependencyAssets();
  291. assetObject = AssetObject.Create(m_Task.AssetName, e.Asset, dependencyAssets, m_Task.ResourceObject.Target, m_ResourceHelper, m_ResourceLoader);
  292. m_ResourceLoader.m_AssetPool.Register(assetObject, true);
  293. m_ResourceLoader.m_AssetToResourceMap.Add(e.Asset, m_Task.ResourceObject.Target);
  294. foreach (object dependencyAsset in dependencyAssets)
  295. {
  296. object dependencyResource = null;
  297. if (m_ResourceLoader.m_AssetToResourceMap.TryGetValue(dependencyAsset, out dependencyResource))
  298. {
  299. m_Task.ResourceObject.AddDependencyResource(dependencyResource);
  300. }
  301. else
  302. {
  303. throw new GameFrameworkException("Can not find dependency resource.");
  304. }
  305. }
  306. }
  307. s_LoadingAssetNames.Remove(m_Task.AssetName);
  308. OnAssetObjectReady(assetObject);
  309. }
  310. private void OnLoadResourceAgentHelperError(object sender, LoadResourceAgentHelperErrorEventArgs e)
  311. {
  312. OnError(e.Status, e.ErrorMessage);
  313. }
  314. }
  315. }
  316. }
  317. }