VersionController.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. using GFGGame.Launcher;
  2. //using VEngine;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using UnityEngine;
  6. using YooAsset;
  7. //using dnlib.PE;
  8. //using VEngine;
  9. //using UnityEngine.Events;
  10. namespace GFGGame
  11. {
  12. public class VersionController : SingletonMonoBase<VersionController>
  13. {
  14. //private UpdateVersions updateVersions;
  15. public const string PackageName_GameLogic = "GameLogic";
  16. public const string PackageName_GameArt = "ArtRes";
  17. private string[] packageNameArr = new string[] {PackageName_GameLogic, PackageName_GameArt };
  18. private Dictionary<string, bool> packageStateDic = new Dictionary<string, bool>();
  19. /// <summary>
  20. /// 包裹的版本信息
  21. /// </summary>
  22. public string PackageVersion { set; get; }
  23. /// <summary>
  24. /// 下载器
  25. /// </summary>
  26. public ResourceDownloaderOperation Downloader { set; get; }
  27. public void Init()
  28. {
  29. // 初始化资源系统
  30. YooAssets.Initialize();
  31. StartCoroutine(InitVersion());
  32. }
  33. public IEnumerator InitVersion()
  34. {
  35. //VEngine.Logger.Loggable = false;
  36. //EncryptHelper.resKey = LauncherConfig.resKey;
  37. //Versions.DownloadURL = LauncherConfig.CDN_ROOT;
  38. //var operation = Versions.InitializeAsync(LauncherConfig.CDN_ROOT);
  39. //yield return operation;
  40. yield return InitGameLogicPackage();
  41. yield return InitGameArtPackage();
  42. yield return GetStaticVersion(PackageName_GameLogic);
  43. yield return UpdateManifest(PackageName_GameLogic);
  44. yield return GetStaticVersion(PackageName_GameArt);
  45. yield return UpdateManifest(PackageName_GameArt);
  46. OnPackageDownloadCompleted(null);
  47. }
  48. private IEnumerator InitGameLogicPackage()
  49. {
  50. // 创建默认的资源包
  51. string packageName = PackageName_GameLogic;
  52. var package = YooAssets.TryGetPackage(packageName);
  53. if (package == null)
  54. {
  55. package = YooAssets.CreatePackage(packageName);
  56. YooAssets.SetDefaultPackage(package);
  57. }
  58. var playMode = GameLauncher.Instance.PlayMode;
  59. InitializationOperation initializationOperation = null;
  60. if (playMode == EPlayMode.EditorSimulateMode)
  61. {
  62. // 编辑器下的模拟模式
  63. var createParameters = new EditorSimulateModeParameters();
  64. createParameters.SimulateManifestFilePath = EditorSimulateModeHelper.SimulateBuild(packageName);
  65. initializationOperation = package.InitializeAsync(createParameters);
  66. }
  67. else if (playMode == EPlayMode.HostPlayMode)
  68. {
  69. // 联机运行模式
  70. string defaultHostServer = GetHostServerURL(PackageName_GameLogic);
  71. string fallbackHostServer = defaultHostServer;
  72. var createParameters = new HostPlayModeParameters();
  73. //createParameters.DecryptionServices = new GameDecryptionServices();
  74. createParameters.QueryServices = new GameQueryServices();
  75. createParameters.RemoteServices = new RemoteServices(defaultHostServer, fallbackHostServer);
  76. initializationOperation = package.InitializeAsync(createParameters);
  77. }
  78. yield return initializationOperation;
  79. if (initializationOperation.Status != EOperationStatus.Succeed)
  80. {
  81. Debug.LogWarning($"{initializationOperation.Error}");
  82. }
  83. }
  84. private IEnumerator InitGameArtPackage()
  85. {
  86. InitializationOperation initializationOperation = null;
  87. var package = YooAssets.CreatePackage(PackageName_GameArt);
  88. string defaultHostServer = GetHostServerURL(PackageName_GameArt);
  89. string fallbackHostServer = defaultHostServer;
  90. var createParameters = new HostPlayModeParameters();
  91. //createParameters.DecryptionServices = new GameDecryptionServices();
  92. createParameters.QueryServices = new GameQueryServices();
  93. createParameters.RemoteServices = new RemoteServices(defaultHostServer, fallbackHostServer);
  94. initializationOperation = package.InitializeAsync(createParameters);
  95. yield return initializationOperation;
  96. if (initializationOperation.Status != EOperationStatus.Succeed)
  97. {
  98. Debug.LogWarning($"{initializationOperation.Error}");
  99. }
  100. }
  101. private IEnumerator GetStaticVersion(string packageName)
  102. {
  103. var package = YooAssets.GetPackage(packageName);
  104. var operation = package.UpdatePackageVersionAsync();
  105. yield return operation;
  106. if (operation.Status == EOperationStatus.Succeed)
  107. {
  108. VersionController.Instance.PackageVersion = operation.PackageVersion;
  109. Debug.Log($"远端最新版本为: {operation.PackageVersion}");
  110. }
  111. else
  112. {
  113. Debug.LogWarning(operation.Error);
  114. }
  115. }
  116. private IEnumerator UpdateManifest(string packageName)
  117. {
  118. bool savePackageVersion = true;
  119. var package = YooAssets.GetPackage(packageName);
  120. var operation = package.UpdatePackageManifestAsync(VersionController.Instance.PackageVersion, savePackageVersion);
  121. yield return operation;
  122. if (operation.Status != EOperationStatus.Succeed)
  123. {
  124. Debug.LogWarning(operation.Error);
  125. Alert.Show("更新版本信息失败,请检测网络链接后重试。")
  126. .SetLeftButton(true, "重试", (data) => { StartCoroutine(UpdateManifest(packageName)); });
  127. }
  128. }
  129. void CreateDownloader(string packageName)
  130. {
  131. int downloadingMaxNum = 10;
  132. int failedTryAgain = 3;
  133. ResourcePackage package = YooAssets.GetPackage(packageName);
  134. var downloaderOperation = package.CreateResourceDownloader(downloadingMaxNum, failedTryAgain);
  135. VersionController.Instance.Downloader = downloaderOperation;
  136. if (downloaderOperation.TotalDownloadCount == 0)
  137. {
  138. OnPackageDownloadCompleted(packageName);
  139. }
  140. else
  141. {
  142. //A total of 10 files were found that need to be downloaded
  143. Debug.Log($"Found total {downloaderOperation.TotalDownloadCount} files that need download !");
  144. // 发现新更新文件后,挂起流程系统
  145. // 注意:开发者需要在下载前检测磁盘空间不足
  146. int totalDownloadCount = downloaderOperation.TotalDownloadCount;
  147. long totalDownloadBytes = downloaderOperation.TotalDownloadBytes;
  148. float sizeMB = totalDownloadBytes / 1048576f;
  149. sizeMB = Mathf.Clamp(sizeMB, 0.1f, float.MaxValue);
  150. string totalSizeMB = sizeMB.ToString("f1");
  151. string message = $"游戏有新的版本,{packageName}需要更新{totalSizeMB}MB大小的内容";
  152. Alert.Show(message)
  153. .SetLeftButton(true, "更新", (data) =>
  154. {
  155. StartCoroutine(BeginDownload(downloaderOperation, packageName));
  156. });
  157. }
  158. }
  159. private IEnumerator BeginDownload(ResourceDownloaderOperation downloaderOperation, string packageName)
  160. {
  161. // 注册下载回调
  162. downloaderOperation.OnDownloadErrorCallback =
  163. (fileName, error) =>
  164. {
  165. Debug.LogError($"加载{fileName}失败 {error}");
  166. };
  167. downloaderOperation.OnDownloadProgressCallback =
  168. (totalDownloadCount, currentDownloadCount, totalDownloadSizeBytes, currentDownloadSizeBytes) =>
  169. {
  170. string currentSizeMB = (currentDownloadSizeBytes / 1048576f).ToString("f1");
  171. string totalSizeMB = (totalDownloadSizeBytes / 1048576f).ToString("f1");
  172. var progress = currentDownloadSizeBytes / totalDownloadSizeBytes;
  173. LauncherView.Instance.SetDesc($"正在下载资源,{currentDownloadCount}/{totalDownloadCount}", $"{currentSizeMB}MB/{totalSizeMB}MB", true);
  174. LauncherView.Instance.SetProgress((int)(progress * 100));
  175. };
  176. downloaderOperation.BeginDownload();
  177. yield return downloaderOperation;
  178. // 检测下载结果
  179. if (downloaderOperation.Status != EOperationStatus.Succeed)
  180. {
  181. Alert.Show("下载失败!请检查网络状态后重试。")
  182. .SetLeftButton(true, "重试", (data) =>
  183. {
  184. StartCoroutine(BeginDownload(downloaderOperation, packageName));
  185. });
  186. yield break;
  187. }
  188. OnPackageDownloadCompleted(packageName);
  189. }
  190. private void OnPackageDownloadCompleted(string packageNameCompleted)
  191. {
  192. if(packageNameCompleted != null)
  193. {
  194. packageStateDic[packageNameCompleted] = true;
  195. }
  196. //if(updateVersions != null)
  197. //{
  198. // updateVersions.Override();
  199. //}
  200. foreach (var packageName in packageNameArr)
  201. {
  202. packageStateDic.TryGetValue(packageName, out bool done);
  203. if(!done)
  204. {
  205. CreateDownloader(packageName);
  206. return;
  207. }
  208. }
  209. LauncherController.OnVersionCompleted();
  210. }
  211. /// <summary>
  212. /// 获取资源服务器地址
  213. /// </summary>
  214. private string GetHostServerURL(string packageName)
  215. {
  216. string hostServerIP = "http://127.0.0.1";
  217. #if UNITY_EDITOR
  218. if (UnityEditor.EditorUserBuildSettings.activeBuildTarget == UnityEditor.BuildTarget.Android)
  219. return $"{hostServerIP}/CDN/Android/{packageName}";
  220. else if (UnityEditor.EditorUserBuildSettings.activeBuildTarget == UnityEditor.BuildTarget.iOS)
  221. return $"{hostServerIP}/CDN/IPhone/{packageName}";
  222. else if (UnityEditor.EditorUserBuildSettings.activeBuildTarget == UnityEditor.BuildTarget.WebGL)
  223. return $"{hostServerIP}/CDN/WebGL/{packageName}";
  224. else
  225. return $"{hostServerIP}/CDN/PC/{packageName}";
  226. #else
  227. if (Application.platform == RuntimePlatform.Android)
  228. return $"{hostServerIP}/CDN/Android/{packageName}";
  229. else if (Application.platform == RuntimePlatform.IPhonePlayer)
  230. return $"{hostServerIP}/CDN/IPhone/{packageName}";
  231. else if (Application.platform == RuntimePlatform.WebGLPlayer)
  232. return $"{hostServerIP}/CDN/WebGL/{packageName}";
  233. else
  234. return $"{hostServerIP}/CDN/PC/{packageName}";
  235. #endif
  236. }
  237. /// <summary>
  238. /// 远端资源地址查询服务类
  239. /// </summary>
  240. private class RemoteServices : IRemoteServices
  241. {
  242. private readonly string _defaultHostServer;
  243. private readonly string _fallbackHostServer;
  244. public RemoteServices(string defaultHostServer, string fallbackHostServer)
  245. {
  246. _defaultHostServer = defaultHostServer;
  247. _fallbackHostServer = fallbackHostServer;
  248. }
  249. string IRemoteServices.GetRemoteMainURL(string fileName)
  250. {
  251. return $"{_defaultHostServer}/{fileName}";
  252. }
  253. string IRemoteServices.GetRemoteFallbackURL(string fileName)
  254. {
  255. return $"{_fallbackHostServer}/{fileName}";
  256. }
  257. }
  258. //private void StartCheckManifestVersion()
  259. //{
  260. // StartCoroutine(CheckManifestVersion());
  261. //}
  262. //private IEnumerator CheckManifestVersion()
  263. //{
  264. // if (GameLauncher.Instance.PlayMode == EPlayMode.HostPlayMode)
  265. // {
  266. // LogServerHelperHttp.SendNodeLog((int)LogNode.StartCheckVersion);
  267. // // TODO:生产环境这里的清单名字应该使用带 hash 的版本
  268. // updateVersions = Versions.UpdateAsync(nameof(Manifest) + LauncherConfig.manifest_v);
  269. // while (!updateVersions.isDone)
  270. // {
  271. // if (updateVersions.asset != null && updateVersions.asset.assetVersion != null)
  272. // {
  273. // var max = updateVersions.asset.assetVersion.size;
  274. // LauncherView.Instance.SetDesc($"正在校验资源版本...", $"{Utility.FormatBytes(max)}");
  275. // LauncherView.Instance.SetProgress((int)(updateVersions.asset.progress * 100));
  276. // }
  277. // yield return updateVersions;
  278. // };
  279. // if (updateVersions.status == OperationStatus.Failed)
  280. // {
  281. // Alert.Show("更新版本信息失败,请检测网络链接后重试。")
  282. // .SetLeftButton(true, "重试", (data) => { StartCheckManifestVersion(); });
  283. // }
  284. // else
  285. // {
  286. // yield return GetDownloadSize();
  287. // }
  288. // }
  289. // else
  290. // {
  291. // OnComplete();
  292. // }
  293. //}
  294. //private IEnumerator GetDownloadSize()
  295. //{
  296. // var getDownloadSize = Versions.GetDownloadSizeAsync(updateVersions);
  297. // var totalCount = getDownloadSize.bundles.Count;
  298. // while(!getDownloadSize.isDone)
  299. // {
  300. // var remainCount = getDownloadSize.bundles.Count;
  301. // LauncherView.Instance.SetDesc($"正在计算更新内容大小...", $"{ totalCount - remainCount }/{totalCount}");
  302. // yield return getDownloadSize;
  303. // }
  304. // if (getDownloadSize.totalSize > 0 || updateVersions.changed)
  305. // {
  306. // string message = $"游戏有新的版本,需要更新{Utility.FormatBytes(getDownloadSize.totalSize)}大小的内容";
  307. // yield return Alert.Show(message)
  308. // .SetLeftButton(true, "更新", (data) => {
  309. // StartDownload(getDownloadSize);
  310. // });
  311. // yield break;
  312. // }
  313. // else
  314. // {
  315. // OnComplete();
  316. // }
  317. //}
  318. //private void StartDownload(GetDownloadSize getDownloadSize)
  319. //{
  320. // LogServerHelperHttp.SendNodeLog((int)LogNode.StartDownload);
  321. // StartCoroutine(Downloading(getDownloadSize));
  322. //}
  323. //private IEnumerator Downloading(GetDownloadSize getDownloadSize)
  324. //{
  325. // LauncherView.Instance.SetProgress((int)(updateVersions.asset.progress * 100));
  326. // var downloadAsync = Versions.DownloadAsync(getDownloadSize.result.ToArray());
  327. // downloadAsync.updated += downloadAsync =>
  328. // {
  329. // var current = downloadAsync.downloadedBytes;
  330. // var max = downloadAsync.totalSize;
  331. // var speed = Download.TotalBandwidth;
  332. // LauncherView.Instance.SetDesc($"正在下载资源,速度 {Utility.FormatBytes(speed)}/s", $"{Utility.FormatBytes(current)}/{Utility.FormatBytes(max)}", true);
  333. // LauncherView.Instance.SetProgress((int)(downloadAsync.progress * 100));
  334. // };
  335. // yield return downloadAsync;
  336. // if (downloadAsync.status == OperationStatus.Failed)
  337. // {
  338. // Alert.Show("下载失败!请检查网络状态后重试。")
  339. // .SetLeftButton(true, "重试", (data) => {
  340. // StartDownload(getDownloadSize);
  341. // });
  342. // }
  343. // else
  344. // {
  345. // OnComplete();
  346. // }
  347. //}
  348. }
  349. }