ResourceManager.ResourceUpdater.cs 49 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030
  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.Download;
  8. using GameFramework.FileSystem;
  9. using System;
  10. using System.Collections.Generic;
  11. using System.IO;
  12. namespace GameFramework.Resource
  13. {
  14. internal sealed partial class ResourceManager : GameFrameworkModule, IResourceManager
  15. {
  16. /// <summary>
  17. /// 资源更新器。
  18. /// </summary>
  19. private sealed partial class ResourceUpdater
  20. {
  21. private const int CachedHashBytesLength = 4;
  22. private const int CachedBytesLength = 0x1000;
  23. private readonly ResourceManager m_ResourceManager;
  24. private readonly List<ApplyInfo> m_ApplyWaitingInfo;
  25. private readonly List<UpdateInfo> m_UpdateWaitingInfo;
  26. private readonly HashSet<UpdateInfo> m_UpdateWaitingInfoWhilePlaying;
  27. private readonly Dictionary<ResourceName, UpdateInfo> m_UpdateCandidateInfo;
  28. private readonly SortedDictionary<string, List<int>> m_CachedFileSystemsForGenerateReadWriteVersionList;
  29. private readonly List<ResourceName> m_CachedResourceNames;
  30. private readonly byte[] m_CachedHashBytes;
  31. private readonly byte[] m_CachedBytes;
  32. private IDownloadManager m_DownloadManager;
  33. private bool m_CheckResourcesComplete;
  34. private string m_ApplyingResourcePackPath;
  35. private FileStream m_ApplyingResourcePackStream;
  36. private ResourceGroup m_UpdatingResourceGroup;
  37. private int m_GenerateReadWriteVersionListLength;
  38. private int m_CurrentGenerateReadWriteVersionListLength;
  39. private int m_UpdateRetryCount;
  40. private bool m_FailureFlag;
  41. private string m_ReadWriteVersionListFileName;
  42. private string m_ReadWriteVersionListTempFileName;
  43. public GameFrameworkAction<ResourceName, string, string, int, int> ResourceApplySuccess;
  44. public GameFrameworkAction<ResourceName, string, string> ResourceApplyFailure;
  45. public GameFrameworkAction<string, bool> ResourceApplyComplete;
  46. public GameFrameworkAction<ResourceName, string, string, int, int, int> ResourceUpdateStart;
  47. public GameFrameworkAction<ResourceName, string, string, int, int> ResourceUpdateChanged;
  48. public GameFrameworkAction<ResourceName, string, string, int, int> ResourceUpdateSuccess;
  49. public GameFrameworkAction<ResourceName, string, int, int, string> ResourceUpdateFailure;
  50. public GameFrameworkAction<ResourceGroup, bool> ResourceUpdateComplete;
  51. public GameFrameworkAction ResourceUpdateAllComplete;
  52. /// <summary>
  53. /// 初始化资源更新器的新实例。
  54. /// </summary>
  55. /// <param name="resourceManager">资源管理器。</param>
  56. public ResourceUpdater(ResourceManager resourceManager)
  57. {
  58. m_ResourceManager = resourceManager;
  59. m_ApplyWaitingInfo = new List<ApplyInfo>();
  60. m_UpdateWaitingInfo = new List<UpdateInfo>();
  61. m_UpdateWaitingInfoWhilePlaying = new HashSet<UpdateInfo>();
  62. m_UpdateCandidateInfo = new Dictionary<ResourceName, UpdateInfo>();
  63. m_CachedFileSystemsForGenerateReadWriteVersionList = new SortedDictionary<string, List<int>>(StringComparer.Ordinal);
  64. m_CachedResourceNames = new List<ResourceName>();
  65. m_CachedHashBytes = new byte[CachedHashBytesLength];
  66. m_CachedBytes = new byte[CachedBytesLength];
  67. m_DownloadManager = null;
  68. m_CheckResourcesComplete = false;
  69. m_ApplyingResourcePackPath = null;
  70. m_ApplyingResourcePackStream = null;
  71. m_UpdatingResourceGroup = null;
  72. m_GenerateReadWriteVersionListLength = 0;
  73. m_CurrentGenerateReadWriteVersionListLength = 0;
  74. m_UpdateRetryCount = 3;
  75. m_FailureFlag = false;
  76. m_ReadWriteVersionListFileName = Utility.Path.GetRegularPath(Path.Combine(m_ResourceManager.m_ReadWritePath, LocalVersionListFileName));
  77. m_ReadWriteVersionListTempFileName = Utility.Text.Format("{0}.{1}", m_ReadWriteVersionListFileName, TempExtension);
  78. ResourceApplySuccess = null;
  79. ResourceApplyFailure = null;
  80. ResourceApplyComplete = null;
  81. ResourceUpdateStart = null;
  82. ResourceUpdateChanged = null;
  83. ResourceUpdateSuccess = null;
  84. ResourceUpdateFailure = null;
  85. ResourceUpdateComplete = null;
  86. ResourceUpdateAllComplete = null;
  87. }
  88. /// <summary>
  89. /// 获取或设置每更新多少字节的资源,重新生成一次版本资源列表。
  90. /// </summary>
  91. public int GenerateReadWriteVersionListLength
  92. {
  93. get
  94. {
  95. return m_GenerateReadWriteVersionListLength;
  96. }
  97. set
  98. {
  99. m_GenerateReadWriteVersionListLength = value;
  100. }
  101. }
  102. /// <summary>
  103. /// 获取正在应用的资源包路径。
  104. /// </summary>
  105. public string ApplyingResourcePackPath
  106. {
  107. get
  108. {
  109. return m_ApplyingResourcePackPath;
  110. }
  111. }
  112. /// <summary>
  113. /// 获取等待应用资源数量。
  114. /// </summary>
  115. public int ApplyWaitingCount
  116. {
  117. get
  118. {
  119. return m_ApplyWaitingInfo.Count;
  120. }
  121. }
  122. /// <summary>
  123. /// 获取或设置资源更新重试次数。
  124. /// </summary>
  125. public int UpdateRetryCount
  126. {
  127. get
  128. {
  129. return m_UpdateRetryCount;
  130. }
  131. set
  132. {
  133. m_UpdateRetryCount = value;
  134. }
  135. }
  136. /// <summary>
  137. /// 获取正在更新的资源组。
  138. /// </summary>
  139. public IResourceGroup UpdatingResourceGroup
  140. {
  141. get
  142. {
  143. return m_UpdatingResourceGroup;
  144. }
  145. }
  146. /// <summary>
  147. /// 获取等待更新资源数量。
  148. /// </summary>
  149. public int UpdateWaitingCount
  150. {
  151. get
  152. {
  153. return m_UpdateWaitingInfo.Count;
  154. }
  155. }
  156. /// <summary>
  157. /// 获取使用时下载的等待更新资源数量。
  158. /// </summary>
  159. public int UpdateWaitingWhilePlayingCount
  160. {
  161. get
  162. {
  163. return m_UpdateWaitingInfoWhilePlaying.Count;
  164. }
  165. }
  166. /// <summary>
  167. /// 获取候选更新资源数量。
  168. /// </summary>
  169. public int UpdateCandidateCount
  170. {
  171. get
  172. {
  173. return m_UpdateCandidateInfo.Count;
  174. }
  175. }
  176. /// <summary>
  177. /// 资源更新器轮询。
  178. /// </summary>
  179. /// <param name="elapseSeconds">逻辑流逝时间,以秒为单位。</param>
  180. /// <param name="realElapseSeconds">真实流逝时间,以秒为单位。</param>
  181. public void Update(float elapseSeconds, float realElapseSeconds)
  182. {
  183. if (m_ApplyingResourcePackStream != null)
  184. {
  185. while (m_ApplyWaitingInfo.Count > 0)
  186. {
  187. ApplyInfo applyInfo = m_ApplyWaitingInfo[0];
  188. m_ApplyWaitingInfo.RemoveAt(0);
  189. if (ApplyResource(applyInfo))
  190. {
  191. return;
  192. }
  193. }
  194. Array.Clear(m_CachedBytes, 0, CachedBytesLength);
  195. string resourcePackPath = m_ApplyingResourcePackPath;
  196. m_ApplyingResourcePackPath = null;
  197. m_ApplyingResourcePackStream.Dispose();
  198. m_ApplyingResourcePackStream = null;
  199. if (ResourceApplyComplete != null)
  200. {
  201. ResourceApplyComplete(resourcePackPath, !m_FailureFlag);
  202. }
  203. if (m_UpdateCandidateInfo.Count <= 0 && ResourceUpdateAllComplete != null)
  204. {
  205. ResourceUpdateAllComplete();
  206. }
  207. return;
  208. }
  209. if (m_UpdateWaitingInfo.Count > 0)
  210. {
  211. int freeCount = m_DownloadManager.FreeAgentCount - m_DownloadManager.WaitingTaskCount;
  212. if (freeCount > 0)
  213. {
  214. for (int i = 0, count = 0; i < m_UpdateWaitingInfo.Count && count < freeCount; i++)
  215. {
  216. if (DownloadResource(m_UpdateWaitingInfo[i]))
  217. {
  218. count++;
  219. }
  220. }
  221. }
  222. return;
  223. }
  224. }
  225. /// <summary>
  226. /// 关闭并清理资源更新器。
  227. /// </summary>
  228. public void Shutdown()
  229. {
  230. if (m_DownloadManager != null)
  231. {
  232. m_DownloadManager.DownloadStart -= OnDownloadStart;
  233. m_DownloadManager.DownloadUpdate -= OnDownloadUpdate;
  234. m_DownloadManager.DownloadSuccess -= OnDownloadSuccess;
  235. m_DownloadManager.DownloadFailure -= OnDownloadFailure;
  236. }
  237. m_UpdateWaitingInfo.Clear();
  238. m_UpdateCandidateInfo.Clear();
  239. m_CachedFileSystemsForGenerateReadWriteVersionList.Clear();
  240. }
  241. /// <summary>
  242. /// 设置下载管理器。
  243. /// </summary>
  244. /// <param name="downloadManager">下载管理器。</param>
  245. public void SetDownloadManager(IDownloadManager downloadManager)
  246. {
  247. if (downloadManager == null)
  248. {
  249. throw new GameFrameworkException("Download manager is invalid.");
  250. }
  251. m_DownloadManager = downloadManager;
  252. m_DownloadManager.DownloadStart += OnDownloadStart;
  253. m_DownloadManager.DownloadUpdate += OnDownloadUpdate;
  254. m_DownloadManager.DownloadSuccess += OnDownloadSuccess;
  255. m_DownloadManager.DownloadFailure += OnDownloadFailure;
  256. }
  257. /// <summary>
  258. /// 增加资源更新。
  259. /// </summary>
  260. /// <param name="resourceName">资源名称。</param>
  261. /// <param name="fileSystemName">资源所在的文件系统名称。</param>
  262. /// <param name="loadType">资源加载方式。</param>
  263. /// <param name="length">资源大小。</param>
  264. /// <param name="hashCode">资源哈希值。</param>
  265. /// <param name="compressedLength">压缩后大小。</param>
  266. /// <param name="compressedHashCode">压缩后哈希值。</param>
  267. /// <param name="resourcePath">资源路径。</param>
  268. public void AddResourceUpdate(ResourceName resourceName, string fileSystemName, LoadType loadType, int length, int hashCode, int compressedLength, int compressedHashCode, string resourcePath)
  269. {
  270. m_UpdateCandidateInfo.Add(resourceName, new UpdateInfo(resourceName, fileSystemName, loadType, length, hashCode, compressedLength, compressedHashCode, resourcePath));
  271. }
  272. /// <summary>
  273. /// 检查资源完成。
  274. /// </summary>
  275. /// <param name="needGenerateReadWriteVersionList">是否需要生成读写区版本资源列表。</param>
  276. public void CheckResourceComplete(bool needGenerateReadWriteVersionList)
  277. {
  278. m_CheckResourcesComplete = true;
  279. if (needGenerateReadWriteVersionList)
  280. {
  281. GenerateReadWriteVersionList();
  282. }
  283. }
  284. /// <summary>
  285. /// 应用指定资源包的资源。
  286. /// </summary>
  287. /// <param name="resourcePackPath">要应用的资源包路径。</param>
  288. public void ApplyResources(string resourcePackPath)
  289. {
  290. if (!m_CheckResourcesComplete)
  291. {
  292. throw new GameFrameworkException("You must check resources complete first.");
  293. }
  294. if (m_ApplyingResourcePackStream != null)
  295. {
  296. throw new GameFrameworkException(Utility.Text.Format("There is already a resource pack '{0}' being applied.", m_ApplyingResourcePackPath));
  297. }
  298. if (m_UpdatingResourceGroup != null)
  299. {
  300. throw new GameFrameworkException(Utility.Text.Format("There is already a resource group '{0}' being updated.", m_UpdatingResourceGroup.Name));
  301. }
  302. if (m_UpdateWaitingInfoWhilePlaying.Count > 0)
  303. {
  304. throw new GameFrameworkException("There are already some resources being updated while playing.");
  305. }
  306. try
  307. {
  308. long length = 0L;
  309. ResourcePackVersionList versionList = default(ResourcePackVersionList);
  310. using (FileStream fileStream = new FileStream(resourcePackPath, FileMode.Open, FileAccess.Read))
  311. {
  312. length = fileStream.Length;
  313. versionList = m_ResourceManager.m_ResourcePackVersionListSerializer.Deserialize(fileStream);
  314. }
  315. if (!versionList.IsValid)
  316. {
  317. throw new GameFrameworkException("Deserialize resource pack version list failure.");
  318. }
  319. if (versionList.Offset + versionList.Length != length)
  320. {
  321. throw new GameFrameworkException("Resource pack length is invalid.");
  322. }
  323. m_ApplyingResourcePackPath = resourcePackPath;
  324. m_ApplyingResourcePackStream = new FileStream(resourcePackPath, FileMode.Open, FileAccess.Read);
  325. m_ApplyingResourcePackStream.Position = versionList.Offset;
  326. m_FailureFlag = false;
  327. ResourcePackVersionList.Resource[] resources = versionList.GetResources();
  328. foreach (ResourcePackVersionList.Resource resource in resources)
  329. {
  330. ResourceName resourceName = new ResourceName(resource.Name, resource.Variant, resource.Extension);
  331. UpdateInfo updateInfo = null;
  332. if (!m_UpdateCandidateInfo.TryGetValue(resourceName, out updateInfo))
  333. {
  334. continue;
  335. }
  336. if (updateInfo.LoadType == (LoadType)resource.LoadType && updateInfo.Length == resource.Length && updateInfo.HashCode == resource.HashCode)
  337. {
  338. m_ApplyWaitingInfo.Add(new ApplyInfo(resourceName, updateInfo.FileSystemName, (LoadType)resource.LoadType, resource.Offset, resource.Length, resource.HashCode, resource.CompressedLength, resource.CompressedHashCode, updateInfo.ResourcePath));
  339. }
  340. }
  341. }
  342. catch (Exception exception)
  343. {
  344. if (m_ApplyingResourcePackStream != null)
  345. {
  346. m_ApplyingResourcePackStream.Dispose();
  347. m_ApplyingResourcePackStream = null;
  348. }
  349. throw new GameFrameworkException(Utility.Text.Format("Apply resources '{0}' with exception '{1}'.", resourcePackPath, exception), exception);
  350. }
  351. }
  352. /// <summary>
  353. /// 更新指定资源组的资源。
  354. /// </summary>
  355. /// <param name="resourceGroup">要更新的资源组。</param>
  356. public void UpdateResources(ResourceGroup resourceGroup)
  357. {
  358. if (m_DownloadManager == null)
  359. {
  360. throw new GameFrameworkException("You must set download manager first.");
  361. }
  362. if (!m_CheckResourcesComplete)
  363. {
  364. throw new GameFrameworkException("You must check resources complete first.");
  365. }
  366. if (m_ApplyingResourcePackStream != null)
  367. {
  368. throw new GameFrameworkException(Utility.Text.Format("There is already a resource pack '{0}' being applied.", m_ApplyingResourcePackPath));
  369. }
  370. if (m_UpdatingResourceGroup != null)
  371. {
  372. throw new GameFrameworkException(Utility.Text.Format("There is already a resource group '{0}' being updated.", m_UpdatingResourceGroup.Name));
  373. }
  374. if (string.IsNullOrEmpty(resourceGroup.Name))
  375. {
  376. foreach (KeyValuePair<ResourceName, UpdateInfo> updateInfo in m_UpdateCandidateInfo)
  377. {
  378. m_UpdateWaitingInfo.Add(updateInfo.Value);
  379. }
  380. }
  381. else
  382. {
  383. resourceGroup.InternalGetResourceNames(m_CachedResourceNames);
  384. foreach (ResourceName resourceName in m_CachedResourceNames)
  385. {
  386. UpdateInfo updateInfo = null;
  387. if (!m_UpdateCandidateInfo.TryGetValue(resourceName, out updateInfo))
  388. {
  389. continue;
  390. }
  391. m_UpdateWaitingInfo.Add(updateInfo);
  392. }
  393. m_CachedResourceNames.Clear();
  394. }
  395. m_UpdatingResourceGroup = resourceGroup;
  396. m_FailureFlag = false;
  397. }
  398. /// <summary>
  399. /// 停止更新资源。
  400. /// </summary>
  401. public void StopUpdateResources()
  402. {
  403. if (m_DownloadManager == null)
  404. {
  405. throw new GameFrameworkException("You must set download manager first.");
  406. }
  407. if (!m_CheckResourcesComplete)
  408. {
  409. throw new GameFrameworkException("You must check resources complete first.");
  410. }
  411. if (m_ApplyingResourcePackStream != null)
  412. {
  413. throw new GameFrameworkException(Utility.Text.Format("There is already a resource pack '{0}' being applied.", m_ApplyingResourcePackPath));
  414. }
  415. if (m_UpdatingResourceGroup == null)
  416. {
  417. throw new GameFrameworkException("There is no resource group being updated.");
  418. }
  419. m_UpdateWaitingInfo.Clear();
  420. m_UpdatingResourceGroup = null;
  421. }
  422. /// <summary>
  423. /// 更新指定资源。
  424. /// </summary>
  425. /// <param name="resourceName">要更新的资源名称。</param>
  426. public void UpdateResource(ResourceName resourceName)
  427. {
  428. if (m_DownloadManager == null)
  429. {
  430. throw new GameFrameworkException("You must set download manager first.");
  431. }
  432. if (!m_CheckResourcesComplete)
  433. {
  434. throw new GameFrameworkException("You must check resources complete first.");
  435. }
  436. if (m_ApplyingResourcePackStream != null)
  437. {
  438. throw new GameFrameworkException(Utility.Text.Format("There is already a resource pack '{0}' being applied.", m_ApplyingResourcePackPath));
  439. }
  440. UpdateInfo updateInfo = null;
  441. if (m_UpdateCandidateInfo.TryGetValue(resourceName, out updateInfo) && m_UpdateWaitingInfoWhilePlaying.Add(updateInfo))
  442. {
  443. DownloadResource(updateInfo);
  444. }
  445. }
  446. private bool ApplyResource(ApplyInfo applyInfo)
  447. {
  448. long position = m_ApplyingResourcePackStream.Position;
  449. try
  450. {
  451. bool compressed = applyInfo.Length != applyInfo.CompressedLength || applyInfo.HashCode != applyInfo.CompressedHashCode;
  452. int bytesRead = 0;
  453. int bytesLeft = applyInfo.CompressedLength;
  454. string directory = Path.GetDirectoryName(applyInfo.ResourcePath);
  455. if (!Directory.Exists(directory))
  456. {
  457. Directory.CreateDirectory(directory);
  458. }
  459. m_ApplyingResourcePackStream.Position += applyInfo.Offset;
  460. using (FileStream fileStream = new FileStream(applyInfo.ResourcePath, FileMode.Create, FileAccess.ReadWrite))
  461. {
  462. while ((bytesRead = m_ApplyingResourcePackStream.Read(m_CachedBytes, 0, bytesLeft < CachedBytesLength ? bytesLeft : CachedBytesLength)) > 0)
  463. {
  464. bytesLeft -= bytesRead;
  465. fileStream.Write(m_CachedBytes, 0, bytesRead);
  466. }
  467. if (compressed)
  468. {
  469. fileStream.Position = 0L;
  470. int hashCode = Utility.Verifier.GetCrc32(fileStream);
  471. if (hashCode != applyInfo.CompressedHashCode)
  472. {
  473. if (ResourceApplyFailure != null)
  474. {
  475. string errorMessage = Utility.Text.Format("Resource compressed hash code error, need '{0}', applied '{1}'.", applyInfo.CompressedHashCode, hashCode);
  476. ResourceApplyFailure(applyInfo.ResourceName, m_ApplyingResourcePackPath, errorMessage);
  477. }
  478. m_FailureFlag = true;
  479. return false;
  480. }
  481. if (m_ResourceManager.m_DecompressCachedStream == null)
  482. {
  483. m_ResourceManager.m_DecompressCachedStream = new MemoryStream();
  484. }
  485. fileStream.Position = 0L;
  486. m_ResourceManager.m_DecompressCachedStream.Position = 0L;
  487. m_ResourceManager.m_DecompressCachedStream.SetLength(0L);
  488. if (!Utility.Compression.Decompress(fileStream, m_ResourceManager.m_DecompressCachedStream))
  489. {
  490. if (ResourceApplyFailure != null)
  491. {
  492. string errorMessage = Utility.Text.Format("Unable to decompress resource '{0}'.", applyInfo.ResourcePath);
  493. ResourceApplyFailure(applyInfo.ResourceName, m_ApplyingResourcePackPath, errorMessage);
  494. }
  495. m_FailureFlag = true;
  496. return false;
  497. }
  498. fileStream.Position = 0L;
  499. fileStream.SetLength(0L);
  500. fileStream.Write(m_ResourceManager.m_DecompressCachedStream.GetBuffer(), 0, (int)m_ResourceManager.m_DecompressCachedStream.Length);
  501. }
  502. else
  503. {
  504. int hashCode = 0;
  505. fileStream.Position = 0L;
  506. if (applyInfo.LoadType == LoadType.LoadFromMemoryAndQuickDecrypt || applyInfo.LoadType == LoadType.LoadFromMemoryAndDecrypt
  507. || applyInfo.LoadType == LoadType.LoadFromBinaryAndQuickDecrypt || applyInfo.LoadType == LoadType.LoadFromBinaryAndDecrypt)
  508. {
  509. Utility.Converter.GetBytes(applyInfo.HashCode, m_CachedHashBytes);
  510. if (applyInfo.LoadType == LoadType.LoadFromMemoryAndQuickDecrypt || applyInfo.LoadType == LoadType.LoadFromBinaryAndQuickDecrypt)
  511. {
  512. hashCode = Utility.Verifier.GetCrc32(fileStream, m_CachedHashBytes, Utility.Encryption.QuickEncryptLength);
  513. }
  514. else if (applyInfo.LoadType == LoadType.LoadFromMemoryAndDecrypt || applyInfo.LoadType == LoadType.LoadFromBinaryAndDecrypt)
  515. {
  516. hashCode = Utility.Verifier.GetCrc32(fileStream, m_CachedHashBytes, applyInfo.Length);
  517. }
  518. Array.Clear(m_CachedHashBytes, 0, CachedHashBytesLength);
  519. }
  520. else
  521. {
  522. hashCode = Utility.Verifier.GetCrc32(fileStream);
  523. }
  524. if (hashCode != applyInfo.HashCode)
  525. {
  526. if (ResourceApplyFailure != null)
  527. {
  528. string errorMessage = Utility.Text.Format("Resource hash code error, need '{0}', applied '{1}'.", applyInfo.HashCode, hashCode);
  529. ResourceApplyFailure(applyInfo.ResourceName, m_ApplyingResourcePackPath, errorMessage);
  530. }
  531. m_FailureFlag = true;
  532. return false;
  533. }
  534. }
  535. }
  536. if (applyInfo.UseFileSystem)
  537. {
  538. IFileSystem fileSystem = m_ResourceManager.GetFileSystem(applyInfo.FileSystemName, false);
  539. bool retVal = fileSystem.WriteFile(applyInfo.ResourceName.FullName, applyInfo.ResourcePath);
  540. if (File.Exists(applyInfo.ResourcePath))
  541. {
  542. File.Delete(applyInfo.ResourcePath);
  543. }
  544. if (!retVal)
  545. {
  546. if (ResourceApplyFailure != null)
  547. {
  548. string errorMessage = Utility.Text.Format("Unable to write resource '{0}' to file system '{1}'.", applyInfo.ResourcePath, applyInfo.FileSystemName);
  549. ResourceApplyFailure(applyInfo.ResourceName, m_ApplyingResourcePackPath, errorMessage);
  550. }
  551. m_FailureFlag = true;
  552. return false;
  553. }
  554. }
  555. string downloadingResource = Utility.Text.Format("{0}.download", applyInfo.ResourcePath);
  556. if (File.Exists(downloadingResource))
  557. {
  558. File.Delete(downloadingResource);
  559. }
  560. m_UpdateCandidateInfo.Remove(applyInfo.ResourceName);
  561. m_ResourceManager.m_ResourceInfos[applyInfo.ResourceName].MarkReady();
  562. m_ResourceManager.m_ReadWriteResourceInfos.Add(applyInfo.ResourceName, new ReadWriteResourceInfo(applyInfo.FileSystemName, applyInfo.LoadType, applyInfo.Length, applyInfo.HashCode));
  563. if (ResourceApplySuccess != null)
  564. {
  565. ResourceApplySuccess(applyInfo.ResourceName, applyInfo.ResourcePath, m_ApplyingResourcePackPath, applyInfo.Length, applyInfo.CompressedLength);
  566. }
  567. m_CurrentGenerateReadWriteVersionListLength += applyInfo.CompressedLength;
  568. if (m_ApplyWaitingInfo.Count <= 0 || m_CurrentGenerateReadWriteVersionListLength >= m_GenerateReadWriteVersionListLength)
  569. {
  570. GenerateReadWriteVersionList();
  571. return true;
  572. }
  573. return false;
  574. }
  575. catch (Exception exception)
  576. {
  577. if (ResourceApplyFailure != null)
  578. {
  579. ResourceApplyFailure(applyInfo.ResourceName, m_ApplyingResourcePackPath, exception.ToString());
  580. }
  581. m_FailureFlag = true;
  582. return false;
  583. }
  584. finally
  585. {
  586. m_ApplyingResourcePackStream.Position = position;
  587. if (m_ResourceManager.m_DecompressCachedStream != null)
  588. {
  589. m_ResourceManager.m_DecompressCachedStream.Position = 0L;
  590. m_ResourceManager.m_DecompressCachedStream.SetLength(0L);
  591. }
  592. }
  593. }
  594. private bool DownloadResource(UpdateInfo updateInfo)
  595. {
  596. if (updateInfo.Downloading)
  597. {
  598. return false;
  599. }
  600. updateInfo.Downloading = true;
  601. string resourceFullNameWithCrc32 = updateInfo.ResourceName.Variant != null ? Utility.Text.Format("{0}.{1}.{2:x8}.{3}", updateInfo.ResourceName.Name, updateInfo.ResourceName.Variant, updateInfo.HashCode, DefaultExtension) : Utility.Text.Format("{0}.{1:x8}.{2}", updateInfo.ResourceName.Name, updateInfo.HashCode, DefaultExtension);
  602. m_DownloadManager.AddDownload(updateInfo.ResourcePath, Utility.Path.GetRemotePath(Path.Combine(m_ResourceManager.m_UpdatePrefixUri, resourceFullNameWithCrc32)), updateInfo);
  603. return true;
  604. }
  605. private void GenerateReadWriteVersionList()
  606. {
  607. FileStream fileStream = null;
  608. try
  609. {
  610. fileStream = new FileStream(m_ReadWriteVersionListTempFileName, FileMode.Create, FileAccess.Write);
  611. LocalVersionList.Resource[] resources = m_ResourceManager.m_ReadWriteResourceInfos.Count > 0 ? new LocalVersionList.Resource[m_ResourceManager.m_ReadWriteResourceInfos.Count] : null;
  612. if (resources != null)
  613. {
  614. int index = 0;
  615. foreach (KeyValuePair<ResourceName, ReadWriteResourceInfo> i in m_ResourceManager.m_ReadWriteResourceInfos)
  616. {
  617. resources[index] = new LocalVersionList.Resource(i.Key.Name, i.Key.Variant, i.Key.Extension, (byte)i.Value.LoadType, i.Value.Length, i.Value.HashCode);
  618. if (i.Value.UseFileSystem)
  619. {
  620. List<int> resourceIndexes = null;
  621. if (!m_CachedFileSystemsForGenerateReadWriteVersionList.TryGetValue(i.Value.FileSystemName, out resourceIndexes))
  622. {
  623. resourceIndexes = new List<int>();
  624. m_CachedFileSystemsForGenerateReadWriteVersionList.Add(i.Value.FileSystemName, resourceIndexes);
  625. }
  626. resourceIndexes.Add(index);
  627. }
  628. index++;
  629. }
  630. }
  631. LocalVersionList.FileSystem[] fileSystems = m_CachedFileSystemsForGenerateReadWriteVersionList.Count > 0 ? new LocalVersionList.FileSystem[m_CachedFileSystemsForGenerateReadWriteVersionList.Count] : null;
  632. if (fileSystems != null)
  633. {
  634. int index = 0;
  635. foreach (KeyValuePair<string, List<int>> i in m_CachedFileSystemsForGenerateReadWriteVersionList)
  636. {
  637. fileSystems[index++] = new LocalVersionList.FileSystem(i.Key, i.Value.ToArray());
  638. i.Value.Clear();
  639. }
  640. }
  641. LocalVersionList versionList = new LocalVersionList(resources, fileSystems);
  642. if (!m_ResourceManager.m_ReadWriteVersionListSerializer.Serialize(fileStream, versionList))
  643. {
  644. throw new GameFrameworkException("Serialize read-write version list failure.");
  645. }
  646. if (fileStream != null)
  647. {
  648. fileStream.Dispose();
  649. fileStream = null;
  650. }
  651. }
  652. catch (Exception exception)
  653. {
  654. if (fileStream != null)
  655. {
  656. fileStream.Dispose();
  657. fileStream = null;
  658. }
  659. if (File.Exists(m_ReadWriteVersionListTempFileName))
  660. {
  661. File.Delete(m_ReadWriteVersionListTempFileName);
  662. }
  663. throw new GameFrameworkException(Utility.Text.Format("Generate read-write version list exception '{0}'.", exception), exception);
  664. }
  665. if (File.Exists(m_ReadWriteVersionListFileName))
  666. {
  667. File.Delete(m_ReadWriteVersionListFileName);
  668. }
  669. File.Move(m_ReadWriteVersionListTempFileName, m_ReadWriteVersionListFileName);
  670. m_CurrentGenerateReadWriteVersionListLength = 0;
  671. }
  672. private void OnDownloadStart(object sender, DownloadStartEventArgs e)
  673. {
  674. UpdateInfo updateInfo = e.UserData as UpdateInfo;
  675. if (updateInfo == null)
  676. {
  677. return;
  678. }
  679. if (m_DownloadManager == null)
  680. {
  681. throw new GameFrameworkException("You must set download manager first.");
  682. }
  683. if (e.CurrentLength > int.MaxValue)
  684. {
  685. throw new GameFrameworkException(Utility.Text.Format("File '{0}' is too large.", e.DownloadPath));
  686. }
  687. if (ResourceUpdateStart != null)
  688. {
  689. ResourceUpdateStart(updateInfo.ResourceName, e.DownloadPath, e.DownloadUri, (int)e.CurrentLength, updateInfo.CompressedLength, updateInfo.RetryCount);
  690. }
  691. }
  692. private void OnDownloadUpdate(object sender, DownloadUpdateEventArgs e)
  693. {
  694. UpdateInfo updateInfo = e.UserData as UpdateInfo;
  695. if (updateInfo == null)
  696. {
  697. return;
  698. }
  699. if (m_DownloadManager == null)
  700. {
  701. throw new GameFrameworkException("You must set download manager first.");
  702. }
  703. if (e.CurrentLength > updateInfo.CompressedLength)
  704. {
  705. m_DownloadManager.RemoveDownload(e.SerialId);
  706. string downloadFile = Utility.Text.Format("{0}.download", e.DownloadPath);
  707. if (File.Exists(downloadFile))
  708. {
  709. File.Delete(downloadFile);
  710. }
  711. string errorMessage = Utility.Text.Format("When download update, downloaded length is larger than compressed length, need '{0}', downloaded '{1}'.", updateInfo.CompressedLength, e.CurrentLength);
  712. DownloadFailureEventArgs downloadFailureEventArgs = DownloadFailureEventArgs.Create(e.SerialId, e.DownloadPath, e.DownloadUri, errorMessage, e.UserData);
  713. OnDownloadFailure(this, downloadFailureEventArgs);
  714. ReferencePool.Release(downloadFailureEventArgs);
  715. return;
  716. }
  717. if (ResourceUpdateChanged != null)
  718. {
  719. ResourceUpdateChanged(updateInfo.ResourceName, e.DownloadPath, e.DownloadUri, (int)e.CurrentLength, updateInfo.CompressedLength);
  720. }
  721. }
  722. private void OnDownloadSuccess(object sender, DownloadSuccessEventArgs e)
  723. {
  724. UpdateInfo updateInfo = e.UserData as UpdateInfo;
  725. if (updateInfo == null)
  726. {
  727. return;
  728. }
  729. try
  730. {
  731. using (FileStream fileStream = new FileStream(e.DownloadPath, FileMode.Open, FileAccess.ReadWrite))
  732. {
  733. bool compressed = updateInfo.Length != updateInfo.CompressedLength || updateInfo.HashCode != updateInfo.CompressedHashCode;
  734. int length = (int)fileStream.Length;
  735. if (length != updateInfo.CompressedLength)
  736. {
  737. fileStream.Close();
  738. string errorMessage = Utility.Text.Format("Resource compressed length error, need '{0}', downloaded '{1}'.", updateInfo.CompressedLength, length);
  739. DownloadFailureEventArgs downloadFailureEventArgs = DownloadFailureEventArgs.Create(e.SerialId, e.DownloadPath, e.DownloadUri, errorMessage, e.UserData);
  740. OnDownloadFailure(this, downloadFailureEventArgs);
  741. ReferencePool.Release(downloadFailureEventArgs);
  742. return;
  743. }
  744. if (compressed)
  745. {
  746. fileStream.Position = 0L;
  747. int hashCode = Utility.Verifier.GetCrc32(fileStream);
  748. if (hashCode != updateInfo.CompressedHashCode)
  749. {
  750. fileStream.Close();
  751. string errorMessage = Utility.Text.Format("Resource compressed hash code error, need '{0}', downloaded '{1}'.", updateInfo.CompressedHashCode, hashCode);
  752. DownloadFailureEventArgs downloadFailureEventArgs = DownloadFailureEventArgs.Create(e.SerialId, e.DownloadPath, e.DownloadUri, errorMessage, e.UserData);
  753. OnDownloadFailure(this, downloadFailureEventArgs);
  754. ReferencePool.Release(downloadFailureEventArgs);
  755. return;
  756. }
  757. if (m_ResourceManager.m_DecompressCachedStream == null)
  758. {
  759. m_ResourceManager.m_DecompressCachedStream = new MemoryStream();
  760. }
  761. fileStream.Position = 0L;
  762. m_ResourceManager.m_DecompressCachedStream.Position = 0L;
  763. m_ResourceManager.m_DecompressCachedStream.SetLength(0L);
  764. if (!Utility.Compression.Decompress(fileStream, m_ResourceManager.m_DecompressCachedStream))
  765. {
  766. fileStream.Close();
  767. string errorMessage = Utility.Text.Format("Unable to decompress resource '{0}'.", e.DownloadPath);
  768. DownloadFailureEventArgs downloadFailureEventArgs = DownloadFailureEventArgs.Create(e.SerialId, e.DownloadPath, e.DownloadUri, errorMessage, e.UserData);
  769. OnDownloadFailure(this, downloadFailureEventArgs);
  770. ReferencePool.Release(downloadFailureEventArgs);
  771. return;
  772. }
  773. if (m_ResourceManager.m_DecompressCachedStream.Length != updateInfo.Length)
  774. {
  775. fileStream.Close();
  776. string errorMessage = Utility.Text.Format("Resource length error, need '{0}', downloaded '{1}'.", updateInfo.Length, m_ResourceManager.m_DecompressCachedStream.Length);
  777. DownloadFailureEventArgs downloadFailureEventArgs = DownloadFailureEventArgs.Create(e.SerialId, e.DownloadPath, e.DownloadUri, errorMessage, e.UserData);
  778. OnDownloadFailure(this, downloadFailureEventArgs);
  779. ReferencePool.Release(downloadFailureEventArgs);
  780. return;
  781. }
  782. fileStream.Position = 0L;
  783. fileStream.SetLength(0L);
  784. fileStream.Write(m_ResourceManager.m_DecompressCachedStream.GetBuffer(), 0, (int)m_ResourceManager.m_DecompressCachedStream.Length);
  785. }
  786. else
  787. {
  788. int hashCode = 0;
  789. fileStream.Position = 0L;
  790. if (updateInfo.LoadType == LoadType.LoadFromMemoryAndQuickDecrypt || updateInfo.LoadType == LoadType.LoadFromMemoryAndDecrypt
  791. || updateInfo.LoadType == LoadType.LoadFromBinaryAndQuickDecrypt || updateInfo.LoadType == LoadType.LoadFromBinaryAndDecrypt)
  792. {
  793. Utility.Converter.GetBytes(updateInfo.HashCode, m_CachedHashBytes);
  794. if (updateInfo.LoadType == LoadType.LoadFromMemoryAndQuickDecrypt || updateInfo.LoadType == LoadType.LoadFromBinaryAndQuickDecrypt)
  795. {
  796. hashCode = Utility.Verifier.GetCrc32(fileStream, m_CachedHashBytes, Utility.Encryption.QuickEncryptLength);
  797. }
  798. else if (updateInfo.LoadType == LoadType.LoadFromMemoryAndDecrypt || updateInfo.LoadType == LoadType.LoadFromBinaryAndDecrypt)
  799. {
  800. hashCode = Utility.Verifier.GetCrc32(fileStream, m_CachedHashBytes, length);
  801. }
  802. Array.Clear(m_CachedHashBytes, 0, CachedHashBytesLength);
  803. }
  804. else
  805. {
  806. hashCode = Utility.Verifier.GetCrc32(fileStream);
  807. }
  808. if (hashCode != updateInfo.HashCode)
  809. {
  810. fileStream.Close();
  811. string errorMessage = Utility.Text.Format("Resource hash code error, need '{0}', downloaded '{1}'.", updateInfo.HashCode, hashCode);
  812. DownloadFailureEventArgs downloadFailureEventArgs = DownloadFailureEventArgs.Create(e.SerialId, e.DownloadPath, e.DownloadUri, errorMessage, e.UserData);
  813. OnDownloadFailure(this, downloadFailureEventArgs);
  814. ReferencePool.Release(downloadFailureEventArgs);
  815. return;
  816. }
  817. }
  818. }
  819. if (updateInfo.UseFileSystem)
  820. {
  821. IFileSystem fileSystem = m_ResourceManager.GetFileSystem(updateInfo.FileSystemName, false);
  822. bool retVal = fileSystem.WriteFile(updateInfo.ResourceName.FullName, updateInfo.ResourcePath);
  823. if (File.Exists(updateInfo.ResourcePath))
  824. {
  825. File.Delete(updateInfo.ResourcePath);
  826. }
  827. if (!retVal)
  828. {
  829. string errorMessage = Utility.Text.Format("Write resource to file system '{0}' error.", fileSystem.FullPath);
  830. DownloadFailureEventArgs downloadFailureEventArgs = DownloadFailureEventArgs.Create(e.SerialId, e.DownloadPath, e.DownloadUri, errorMessage, e.UserData);
  831. OnDownloadFailure(this, downloadFailureEventArgs);
  832. ReferencePool.Release(downloadFailureEventArgs);
  833. return;
  834. }
  835. }
  836. m_UpdateCandidateInfo.Remove(updateInfo.ResourceName);
  837. m_UpdateWaitingInfo.Remove(updateInfo);
  838. m_UpdateWaitingInfoWhilePlaying.Remove(updateInfo);
  839. m_ResourceManager.m_ResourceInfos[updateInfo.ResourceName].MarkReady();
  840. m_ResourceManager.m_ReadWriteResourceInfos.Add(updateInfo.ResourceName, new ReadWriteResourceInfo(updateInfo.FileSystemName, updateInfo.LoadType, updateInfo.Length, updateInfo.HashCode));
  841. if (ResourceUpdateSuccess != null)
  842. {
  843. ResourceUpdateSuccess(updateInfo.ResourceName, e.DownloadPath, e.DownloadUri, updateInfo.Length, updateInfo.CompressedLength);
  844. }
  845. m_CurrentGenerateReadWriteVersionListLength += updateInfo.CompressedLength;
  846. if (m_UpdateCandidateInfo.Count <= 0 || m_UpdateWaitingInfo.Count + m_UpdateWaitingInfoWhilePlaying.Count <= 0 || m_CurrentGenerateReadWriteVersionListLength >= m_GenerateReadWriteVersionListLength)
  847. {
  848. GenerateReadWriteVersionList();
  849. }
  850. if (m_UpdatingResourceGroup != null && m_UpdateWaitingInfo.Count <= 0)
  851. {
  852. ResourceGroup updatingResourceGroup = m_UpdatingResourceGroup;
  853. m_UpdatingResourceGroup = null;
  854. if (ResourceUpdateComplete != null)
  855. {
  856. ResourceUpdateComplete(updatingResourceGroup, !m_FailureFlag);
  857. }
  858. }
  859. if (m_UpdateCandidateInfo.Count <= 0 && ResourceUpdateAllComplete != null)
  860. {
  861. ResourceUpdateAllComplete();
  862. }
  863. }
  864. catch (Exception exception)
  865. {
  866. string errorMessage = Utility.Text.Format("Update resource '{0}' with error message '{1}'.", e.DownloadPath, exception);
  867. DownloadFailureEventArgs downloadFailureEventArgs = DownloadFailureEventArgs.Create(e.SerialId, e.DownloadPath, e.DownloadUri, errorMessage, e.UserData);
  868. OnDownloadFailure(this, downloadFailureEventArgs);
  869. ReferencePool.Release(downloadFailureEventArgs);
  870. }
  871. finally
  872. {
  873. if (m_ResourceManager.m_DecompressCachedStream != null)
  874. {
  875. m_ResourceManager.m_DecompressCachedStream.Position = 0L;
  876. m_ResourceManager.m_DecompressCachedStream.SetLength(0L);
  877. }
  878. }
  879. }
  880. private void OnDownloadFailure(object sender, DownloadFailureEventArgs e)
  881. {
  882. UpdateInfo updateInfo = e.UserData as UpdateInfo;
  883. if (updateInfo == null)
  884. {
  885. return;
  886. }
  887. if (File.Exists(e.DownloadPath))
  888. {
  889. File.Delete(e.DownloadPath);
  890. }
  891. if (ResourceUpdateFailure != null)
  892. {
  893. ResourceUpdateFailure(updateInfo.ResourceName, e.DownloadUri, updateInfo.RetryCount, m_UpdateRetryCount, e.ErrorMessage);
  894. }
  895. if (updateInfo.RetryCount < m_UpdateRetryCount)
  896. {
  897. updateInfo.Downloading = false;
  898. updateInfo.RetryCount++;
  899. if (m_UpdateWaitingInfoWhilePlaying.Contains(updateInfo))
  900. {
  901. DownloadResource(updateInfo);
  902. }
  903. }
  904. else
  905. {
  906. m_FailureFlag = true;
  907. updateInfo.Downloading = false;
  908. updateInfo.RetryCount = 0;
  909. m_UpdateWaitingInfo.Remove(updateInfo);
  910. m_UpdateWaitingInfoWhilePlaying.Remove(updateInfo);
  911. }
  912. }
  913. }
  914. }
  915. }