HostPlayModeImpl.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. namespace YooAsset
  6. {
  7. internal class HostPlayModeImpl : IBundleServices
  8. {
  9. // 补丁清单
  10. internal PatchManifest AppPatchManifest { private set; get; }
  11. internal PatchManifest LocalPatchManifest { private set; get; }
  12. // 参数相关
  13. private bool _locationToLower;
  14. private bool _clearCacheWhenDirty;
  15. private string _defaultHostServer;
  16. private string _fallbackHostServer;
  17. public bool ClearCacheWhenDirty
  18. {
  19. get { return _clearCacheWhenDirty; }
  20. }
  21. /// <summary>
  22. /// 异步初始化
  23. /// </summary>
  24. public InitializationOperation InitializeAsync(bool locationToLower, bool clearCacheWhenDirty, string defaultHostServer, string fallbackHostServer)
  25. {
  26. _locationToLower = locationToLower;
  27. _clearCacheWhenDirty = clearCacheWhenDirty;
  28. _defaultHostServer = defaultHostServer;
  29. _fallbackHostServer = fallbackHostServer;
  30. var operation = new HostPlayModeInitializationOperation(this);
  31. OperationSystem.StartOperation(operation);
  32. return operation;
  33. }
  34. /// <summary>
  35. /// 异步更新资源版本号
  36. /// </summary>
  37. public UpdateStaticVersionOperation UpdateStaticVersionAsync(int timeout)
  38. {
  39. var operation = new HostPlayModeUpdateStaticVersionOperation(this, timeout);
  40. OperationSystem.StartOperation(operation);
  41. return operation;
  42. }
  43. /// <summary>
  44. /// 异步更新补丁清单
  45. /// </summary>
  46. public UpdateManifestOperation UpdatePatchManifestAsync(int resourceVersion, int timeout)
  47. {
  48. var operation = new HostPlayModeUpdateManifestOperation(this, resourceVersion, timeout);
  49. OperationSystem.StartOperation(operation);
  50. return operation;
  51. }
  52. /// <summary>
  53. /// 异步更新补丁清单(弱联网)
  54. /// </summary>
  55. public UpdateManifestOperation WeaklyUpdatePatchManifestAsync(int resourceVersion)
  56. {
  57. var operation = new HostPlayModeWeaklyUpdateManifestOperation(this, resourceVersion);
  58. OperationSystem.StartOperation(operation);
  59. return operation;
  60. }
  61. /// <summary>
  62. /// 异步更新资源包裹
  63. /// </summary>
  64. public UpdatePackageOperation UpdatePackageAsync(int resourceVersion, int timeout)
  65. {
  66. var operation = new HostPlayModeUpdatePackageOperation(this, resourceVersion, timeout);
  67. OperationSystem.StartOperation(operation);
  68. return operation;
  69. }
  70. /// <summary>
  71. /// 获取资源版本号
  72. /// </summary>
  73. public int GetResourceVersion()
  74. {
  75. if (LocalPatchManifest == null)
  76. return 0;
  77. return LocalPatchManifest.ResourceVersion;
  78. }
  79. /// <summary>
  80. /// 获取未被使用的缓存文件路径集合
  81. /// </summary>
  82. public List<string> ClearUnusedCacheFilePaths()
  83. {
  84. string cacheFolderPath = SandboxHelper.GetCacheFolderPath();
  85. if (Directory.Exists(cacheFolderPath) == false)
  86. return new List<string>();
  87. DirectoryInfo directoryInfo = new DirectoryInfo(cacheFolderPath);
  88. FileInfo[] fileInfos = directoryInfo.GetFiles();
  89. List<string> result = new List<string>(fileInfos.Length);
  90. foreach (FileInfo fileInfo in fileInfos)
  91. {
  92. bool used = false;
  93. foreach (var patchBundle in LocalPatchManifest.BundleList)
  94. {
  95. if (fileInfo.Name == patchBundle.FileName)
  96. {
  97. used = true;
  98. break;
  99. }
  100. }
  101. if (used == false)
  102. result.Add(fileInfo.FullName);
  103. }
  104. return result;
  105. }
  106. /// <summary>
  107. /// 创建下载器
  108. /// </summary>
  109. public PatchDownloaderOperation CreatePatchDownloaderByAll(int fileLoadingMaxNumber, int failedTryAgain)
  110. {
  111. List<BundleInfo> downloadList = GetDownloadListByAll();
  112. var operation = new PatchDownloaderOperation(downloadList, fileLoadingMaxNumber, failedTryAgain);
  113. return operation;
  114. }
  115. private List<BundleInfo> GetDownloadListByAll()
  116. {
  117. List<PatchBundle> downloadList = new List<PatchBundle>(1000);
  118. foreach (var patchBundle in LocalPatchManifest.BundleList)
  119. {
  120. // 忽略缓存文件
  121. if (CacheSystem.IsCached(patchBundle))
  122. continue;
  123. // 忽略APP资源
  124. // 注意:如果是APP资源并且哈希值相同,则不需要下载
  125. if (AppPatchManifest.TryGetPatchBundle(patchBundle.BundleName, out PatchBundle appPatchBundle))
  126. {
  127. if (appPatchBundle.IsBuildin && appPatchBundle.Equals(patchBundle))
  128. continue;
  129. }
  130. downloadList.Add(patchBundle);
  131. }
  132. return ConvertToDownloadList(downloadList);
  133. }
  134. /// <summary>
  135. /// 创建下载器
  136. /// </summary>
  137. public PatchDownloaderOperation CreatePatchDownloaderByTags(string[] tags, int fileLoadingMaxNumber, int failedTryAgain)
  138. {
  139. List<BundleInfo> downloadList = GetDownloadListByTags(tags);
  140. var operation = new PatchDownloaderOperation(downloadList, fileLoadingMaxNumber, failedTryAgain);
  141. return operation;
  142. }
  143. private List<BundleInfo> GetDownloadListByTags(string[] tags)
  144. {
  145. List<PatchBundle> downloadList = new List<PatchBundle>(1000);
  146. foreach (var patchBundle in LocalPatchManifest.BundleList)
  147. {
  148. // 忽略缓存文件
  149. if (CacheSystem.IsCached(patchBundle))
  150. continue;
  151. // 忽略APP资源
  152. // 注意:如果是APP资源并且哈希值相同,则不需要下载
  153. if (AppPatchManifest.TryGetPatchBundle(patchBundle.BundleName, out PatchBundle appPatchBundle))
  154. {
  155. if (appPatchBundle.IsBuildin && appPatchBundle.Equals(patchBundle))
  156. continue;
  157. }
  158. // 如果是纯内置资源,则统一下载
  159. // 注意:可能是新增的或者变化的内置资源
  160. // 注意:可能是由热更资源转换的内置资源
  161. if (patchBundle.IsPureBuildin())
  162. {
  163. downloadList.Add(patchBundle);
  164. }
  165. else
  166. {
  167. // 查询DLC资源
  168. if (patchBundle.HasTag(tags))
  169. {
  170. downloadList.Add(patchBundle);
  171. }
  172. }
  173. }
  174. return ConvertToDownloadList(downloadList);
  175. }
  176. /// <summary>
  177. /// 创建下载器
  178. /// </summary>
  179. public PatchDownloaderOperation CreatePatchDownloaderByPaths(AssetInfo[] assetInfos, int fileLoadingMaxNumber, int failedTryAgain)
  180. {
  181. List<BundleInfo> downloadList = GetDownloadListByPaths(assetInfos);
  182. var operation = new PatchDownloaderOperation(downloadList, fileLoadingMaxNumber, failedTryAgain);
  183. return operation;
  184. }
  185. private List<BundleInfo> GetDownloadListByPaths(AssetInfo[] assetInfos)
  186. {
  187. // 获取资源对象的资源包和所有依赖资源包
  188. List<PatchBundle> checkList = new List<PatchBundle>();
  189. foreach (var assetInfo in assetInfos)
  190. {
  191. if (assetInfo.IsInvalid)
  192. {
  193. YooLogger.Warning(assetInfo.Error);
  194. continue;
  195. }
  196. // 注意:如果补丁清单里未找到资源包会抛出异常!
  197. PatchBundle mainBundle = LocalPatchManifest.GetMainPatchBundle(assetInfo.AssetPath);
  198. if (checkList.Contains(mainBundle) == false)
  199. checkList.Add(mainBundle);
  200. // 注意:如果补丁清单里未找到资源包会抛出异常!
  201. PatchBundle[] dependBundles = LocalPatchManifest.GetAllDependencies(assetInfo.AssetPath);
  202. foreach (var dependBundle in dependBundles)
  203. {
  204. if (checkList.Contains(dependBundle) == false)
  205. checkList.Add(dependBundle);
  206. }
  207. }
  208. List<PatchBundle> downloadList = new List<PatchBundle>(1000);
  209. foreach (var patchBundle in checkList)
  210. {
  211. // 忽略缓存文件
  212. if (CacheSystem.IsCached(patchBundle))
  213. continue;
  214. // 忽略APP资源
  215. // 注意:如果是APP资源并且哈希值相同,则不需要下载
  216. if (AppPatchManifest.TryGetPatchBundle(patchBundle.BundleName, out PatchBundle appPatchBundle))
  217. {
  218. if (appPatchBundle.IsBuildin && appPatchBundle.Equals(patchBundle))
  219. continue;
  220. }
  221. downloadList.Add(patchBundle);
  222. }
  223. return ConvertToDownloadList(downloadList);
  224. }
  225. /// <summary>
  226. /// 创建解压器
  227. /// </summary>
  228. public PatchUnpackerOperation CreatePatchUnpackerByTags(string[] tags, int fileUpackingMaxNumber, int failedTryAgain)
  229. {
  230. List<BundleInfo> unpcakList = GetUnpackListByTags(tags);
  231. var operation = new PatchUnpackerOperation(unpcakList, fileUpackingMaxNumber, failedTryAgain);
  232. return operation;
  233. }
  234. private List<BundleInfo> GetUnpackListByTags(string[] tags)
  235. {
  236. List<PatchBundle> downloadList = new List<PatchBundle>(1000);
  237. foreach (var patchBundle in AppPatchManifest.BundleList)
  238. {
  239. // 如果不是内置资源
  240. if (patchBundle.IsBuildin == false)
  241. continue;
  242. // 忽略缓存文件
  243. if (CacheSystem.IsCached(patchBundle))
  244. continue;
  245. // 查询DLC资源
  246. if (patchBundle.HasTag(tags))
  247. {
  248. downloadList.Add(patchBundle);
  249. }
  250. }
  251. return PatchHelper.ConvertToUnpackList(downloadList);
  252. }
  253. /// <summary>
  254. /// 创建解压器
  255. /// </summary>
  256. public PatchUnpackerOperation CreatePatchUnpackerByAll(int fileUpackingMaxNumber, int failedTryAgain)
  257. {
  258. List<BundleInfo> unpcakList = GetUnpackListByAll();
  259. var operation = new PatchUnpackerOperation(unpcakList, fileUpackingMaxNumber, failedTryAgain);
  260. return operation;
  261. }
  262. private List<BundleInfo> GetUnpackListByAll()
  263. {
  264. List<PatchBundle> downloadList = new List<PatchBundle>(1000);
  265. foreach (var patchBundle in AppPatchManifest.BundleList)
  266. {
  267. // 如果不是内置资源
  268. if (patchBundle.IsBuildin == false)
  269. continue;
  270. // 忽略缓存文件
  271. if (CacheSystem.IsCached(patchBundle))
  272. continue;
  273. downloadList.Add(patchBundle);
  274. }
  275. return PatchHelper.ConvertToUnpackList(downloadList);
  276. }
  277. // WEB相关
  278. public string GetPatchDownloadMainURL(string fileName)
  279. {
  280. return $"{_defaultHostServer}/{fileName}";
  281. }
  282. public string GetPatchDownloadFallbackURL(string fileName)
  283. {
  284. return $"{_fallbackHostServer}/{fileName}";
  285. }
  286. // 下载相关
  287. public List<BundleInfo> ConvertToDownloadList(List<PatchBundle> downloadList)
  288. {
  289. List<BundleInfo> result = new List<BundleInfo>(downloadList.Count);
  290. foreach (var patchBundle in downloadList)
  291. {
  292. var bundleInfo = ConvertToDownloadInfo(patchBundle);
  293. result.Add(bundleInfo);
  294. }
  295. return result;
  296. }
  297. public BundleInfo ConvertToDownloadInfo(PatchBundle patchBundle)
  298. {
  299. string remoteMainURL = GetPatchDownloadMainURL(patchBundle.FileName);
  300. string remoteFallbackURL = GetPatchDownloadFallbackURL(patchBundle.FileName);
  301. BundleInfo bundleInfo = new BundleInfo(patchBundle, BundleInfo.ELoadMode.LoadFromRemote, remoteMainURL, remoteFallbackURL);
  302. return bundleInfo;
  303. }
  304. // 设置资源清单
  305. internal void SetAppPatchManifest(PatchManifest patchManifest)
  306. {
  307. AppPatchManifest = patchManifest;
  308. }
  309. internal void SetLocalPatchManifest(PatchManifest patchManifest)
  310. {
  311. LocalPatchManifest = patchManifest;
  312. LocalPatchManifest.InitAssetPathMapping(_locationToLower);
  313. }
  314. #region IBundleServices接口
  315. private BundleInfo CreateBundleInfo(PatchBundle patchBundle)
  316. {
  317. if (patchBundle == null)
  318. throw new Exception("Should never get here !");
  319. // 查询沙盒资源
  320. if (CacheSystem.IsCached(patchBundle))
  321. {
  322. BundleInfo bundleInfo = new BundleInfo(patchBundle, BundleInfo.ELoadMode.LoadFromCache);
  323. return bundleInfo;
  324. }
  325. // 查询APP资源
  326. if (AppPatchManifest.TryGetPatchBundle(patchBundle.BundleName, out PatchBundle appPatchBundle))
  327. {
  328. if (appPatchBundle.IsBuildin && appPatchBundle.Equals(patchBundle))
  329. {
  330. BundleInfo bundleInfo = new BundleInfo(appPatchBundle, BundleInfo.ELoadMode.LoadFromStreaming);
  331. return bundleInfo;
  332. }
  333. }
  334. // 从服务端下载
  335. return ConvertToDownloadInfo(patchBundle);
  336. }
  337. BundleInfo IBundleServices.GetBundleInfo(AssetInfo assetInfo)
  338. {
  339. if (assetInfo.IsInvalid)
  340. throw new Exception("Should never get here !");
  341. // 注意:如果补丁清单里未找到资源包会抛出异常!
  342. var patchBundle = LocalPatchManifest.GetMainPatchBundle(assetInfo.AssetPath);
  343. return CreateBundleInfo(patchBundle);
  344. }
  345. BundleInfo[] IBundleServices.GetAllDependBundleInfos(AssetInfo assetInfo)
  346. {
  347. if (assetInfo.IsInvalid)
  348. throw new Exception("Should never get here !");
  349. // 注意:如果补丁清单里未找到资源包会抛出异常!
  350. var depends = LocalPatchManifest.GetAllDependencies(assetInfo.AssetPath);
  351. List<BundleInfo> result = new List<BundleInfo>(depends.Length);
  352. foreach (var patchBundle in depends)
  353. {
  354. BundleInfo bundleInfo = CreateBundleInfo(patchBundle);
  355. result.Add(bundleInfo);
  356. }
  357. return result.ToArray();
  358. }
  359. AssetInfo[] IBundleServices.GetAssetInfos(string[] tags)
  360. {
  361. return PatchHelper.GetAssetsInfoByTags(LocalPatchManifest, tags);
  362. }
  363. PatchAsset IBundleServices.TryGetPatchAsset(string assetPath)
  364. {
  365. if (LocalPatchManifest.TryGetPatchAsset(assetPath, out PatchAsset patchAsset))
  366. return patchAsset;
  367. else
  368. return null;
  369. }
  370. string IBundleServices.MappingToAssetPath(string location)
  371. {
  372. return LocalPatchManifest.MappingToAssetPath(location);
  373. }
  374. #endregion
  375. }
  376. }