using GFGGame.Launcher; using VEngine; using System.Collections; using UnityEngine; using System.Reflection; namespace GFGGame { public class VersionController : SingletonMonoBase { private UpdateVersions updateVersions; public void Init() { StartCoroutine(InitVersion()); } public IEnumerator InitVersion() { Versions.DownloadURL = LauncherConfig.CDN_ROOT; var operation = Versions.InitializeAsync(LauncherConfig.CDN_ROOT); yield return operation; VEngine.Logger.I("Initialize: {0}", operation.status); VEngine.Logger.I("API Version: {0}", Versions.APIVersion); VEngine.Logger.I("AppVersion: {0}", Versions.Manifest.appVersion); VEngine.Logger.I("Manifests Version: {0}", Versions.ManifestsVersion); VEngine.Logger.I("PlayerDataPath: {0}", Versions.PlayerDataPath); VEngine.Logger.I("DownloadDataPath: {0}", Versions.DownloadDataPath); VEngine.Logger.I("DownloadURL: {0}", Versions.DownloadURL); StartUpdateManifest(); } private void CheckApkVersion() { var versionTarget = Versions.Manifest.appVersion; var version = Application.version; if(VersionUtil.compare(version, versionTarget)) { DownloadApk(); } else { DownloadRes(); } } private void StartUpdateManifest() { StartCoroutine(CheckManifestVersion()); } private IEnumerator CheckManifestVersion() { if (!Versions.OfflineMode) { // TODO:生产环境这里的清单名字应该使用带 hash 的版本 updateVersions = Versions.UpdateAsync(nameof(Manifest)); while(!updateVersions.isDone) { if(updateVersions.asset != null && updateVersions.asset.assetVersion != null) { var max = updateVersions.asset.assetVersion.size; LauncherView.Instance.SetDesc($"获取版本文件...", $"{Utility.FormatBytes(max)}"); LauncherView.Instance.SetProgress((int)(updateVersions.asset.progress * 100)); } yield return updateVersions; }; if (updateVersions.status == OperationStatus.Failed) { yield return Alert.Show("更新版本信息失败,请检测网络链接后重试。") .SetLeftButton(true, "重试", (data) => { StartUpdateManifest(); }); yield break; } CheckApkVersion(); yield break; } OnComplete(); } private void DownloadApk() { Alert.Show("需要安装新的安装包,请联系研发获取。") .SetLeftButton(true, "知道了", (data) => { Application.Quit(); }); } private void DownloadRes() { StartCoroutine(GetDownloadSize()); } private IEnumerator GetDownloadSize() { Debug.Log("VersionController GetDownloadSize"); var getDownloadSize = Versions.GetDownloadSizeAsync(updateVersions); var totalCount = getDownloadSize.bundles.Count; while(!getDownloadSize.isDone) { var remainCount = getDownloadSize.bundles.Count; LauncherView.Instance.SetDesc($"正在计算更新内容大小...", $"{ totalCount - remainCount }/{totalCount}"); yield return getDownloadSize; } Debug.Log("VersionController GetDownloadSize tips"); if (getDownloadSize.totalSize > 0 || updateVersions.changed) { string message = $"游戏有新的版本,需要更新{Utility.FormatBytes(getDownloadSize.totalSize)}大小的内容"; yield return Alert.Show(message) .SetLeftButton(true, "更新", (data) => { StartDownload(getDownloadSize); }); yield break; } OnComplete(); } private void StartDownload(GetDownloadSize getDownloadSize) { StartCoroutine(Downloading(getDownloadSize)); } private IEnumerator Downloading(GetDownloadSize getDownloadSize) { LauncherView.Instance.SetProgress((int)(updateVersions.asset.progress * 100)); var downloadAsync = Versions.DownloadAsync(getDownloadSize.result.ToArray()); downloadAsync.updated += downloadAsync => { var current = downloadAsync.downloadedBytes; var max = downloadAsync.totalSize; var speed = Download.TotalBandwidth; LauncherView.Instance.SetDesc($"正在下载资源,速度 {Utility.FormatBytes(speed)}/s", $"{Utility.FormatBytes(current)}/{Utility.FormatBytes(max)}"); LauncherView.Instance.SetProgress((int)(downloadAsync.progress * 100)); }; yield return downloadAsync; if (downloadAsync.status == OperationStatus.Failed) { yield return Alert.Show("下载失败!请检查网络状态后重试。") .SetLeftButton(true, "重试", (data) => { StartDownload(getDownloadSize); }); yield break; } OnComplete(); } private void OnComplete() { if(updateVersions != null) { updateVersions.Override(); } LauncherView.Instance.SetDesc($"正在启动游戏..."); LauncherView.Instance.SetProgress(100, () => { StartCoroutine(StartLoadAssemblyHotfix()); }); } IEnumerator StartLoadAssemblyHotfix() { Debug.LogFormat("ILRuntimeLauncher StartLoadAssemblyHotfix"); yield return new WaitForSeconds(0.1f); var dllPath = "Assets/Res/Code/Game.HotUpdate.dll.bytes"; var asset = GFGAsset.Load(dllPath); byte[] assBytes = asset.bytes; //Debug.LogFormat("assBytes != null {0}", assBytes != null); //Debug.LogFormat("assBytes.Length {0}", assBytes.Length); //yield return new WaitForSeconds(0.1f); var pdbPath = "Assets/Res/Code/Game.HotUpdate.pdb.bytes"; asset = GFGAsset.Load(pdbPath); byte[] pdbBytes = asset.bytes; //Debug.LogFormat("pdbBytes != null {0}", pdbBytes != null); //Debug.LogFormat("pdbBytes.Length {0}", pdbBytes.Length); if(LauncherConfig.ILRuntimeMode) { Debug.LogFormat("Assembly Mode ILRuntime"); ILRuntimeLauncher.Instance.LoadAssembly(assBytes, pdbBytes); } else { Debug.LogFormat("Assembly Mode Jit"); StartCoroutine(LoadAssemblyJustInTime(assBytes, pdbBytes)); } GFGAsset.Release(dllPath); GFGAsset.Release(pdbPath); } IEnumerator LoadAssemblyJustInTime(byte[] assBytes, byte[] pdbBytes) { //yield return new WaitForSeconds(0.1f); //mono模式 var assembly = Assembly.Load(assBytes, pdbBytes); //Debug.LogFormat("assembly != null {0}", assembly != null); //yield return new WaitForSeconds(0.1f); System.Type type = assembly.GetType("GFGGame.HotUpdate.HotUpdateEntry"); //Debug.LogFormat("type != null {0}", type != null); //yield return new WaitForSeconds(0.1f); type.GetMethod("Start").Invoke(type, null); yield break; } } }