/// <summary> /// 加载SubPacakge的AssetInfo /// </summary> /// <param name="platform"></param> /// <returns></returns> private List <AssetItem> LoadLocalSubPacakgeAssetInfo(RuntimePlatform platform, AssetsVersionInfo localVersionInfo) { var retList = new List <AssetItem>(); foreach (var kv in localVersionInfo.SubPckMap) { var subPackageInfoPath = BResources.GetAssetsSubPackageInfoPath(BApplication.persistentDataPath, platform, kv.Key); if (File.Exists(subPackageInfoPath)) { var content = File.ReadAllText(subPackageInfoPath); var assetItems = CsvSerializer.DeserializeFromString <List <AssetItem> >(content); retList.AddRange(assetItems); } } return(retList); }
/// <summary> /// 开始版本控制逻辑 /// </summary> /// <param name="serverUrl">服务器配置根目录</param> /// <param name="localSaveAssetsPath">本地根目录</param> /// <param name="onDownloadProccess">任务进度通知(下载完不等于任务完成!)</param> /// <param name="onTaskEndCallback">任务成功\失败通知!</param> /// 返回码: -1:error 0:success async private Task StartVersionControl(UpdateMode updateMode, string serverUrl, string localSaveAssetsPath, string subPackageName, Action <AssetItem, List <AssetItem> > onDownloadProccess, Action <RetStatus, string> onTaskEndCallback) { var platform = BApplication.RuntimePlatform; //目录准备 var platformStr = BApplication.GetRuntimePlatformPath(); var localSavePlatformPath = IPath.Combine(localSaveAssetsPath, platformStr); if (!Directory.Exists(localSavePlatformPath)) { Directory.CreateDirectory(localSavePlatformPath); } //子包模式判断 bool isDownloadSubPackageMode = !string.IsNullOrEmpty(subPackageName); //1.下载服务器version config var serverVersionInfo = new AssetsVersionInfo(); var localVersionInfo = new AssetsVersionInfo(); #region AssetVersion.info下载 BDebug.Log("【版本控制】1.获取版本信息~", "red"); { var ret = await DownloadAssetVersionInfo(serverUrl, localSaveAssetsPath); if (ret.Item1 != null) { await UniTask.SwitchToMainThread(); onTaskEndCallback?.Invoke(RetStatus.Error, ret.Item1); return; } serverVersionInfo = ret.Item2; localVersionInfo = ret.Item3; } #endregion //2.对比版本、获取对应数据 BDebug.Log("【版本控制】2.对比版本信息~", "red"); string err = null; string suc = null; var serverAssetsInfoList = new List <AssetItem>(); var localAssetsInfoList = new List <AssetItem>(); var serverAssetsContent = ""; // switch (updateMode) { case UpdateMode.Compare: case UpdateMode.CompareWithRepair: //CP模式对比版本与Compare一致 { if (isDownloadSubPackageMode) { //分包模式 (err, suc, serverAssetsInfoList, localAssetsInfoList, serverAssetsContent) = GetDownloadSubPackageData(serverUrl, subPackageName, platform, serverVersionInfo, localVersionInfo); } else { //全量下载 (err, suc, serverAssetsInfoList, localAssetsInfoList, serverAssetsContent) = GetDownloadAssetsData(serverUrl, platform, serverVersionInfo, localVersionInfo); } } break; case UpdateMode.Repair: { //服务器路径 var serverAssetInfosUrl = BResources.GetAssetsInfoPath(serverUrl, platform); //下载服务器Assets.info (err, serverAssetsInfoList, serverAssetsContent) = LoadServerAssetInfo(serverAssetInfosUrl); } break; } //返回返回结果,是否继续下载 if (err != null) { BDebug.LogError(err); await UniTask.SwitchToMainThread(); onTaskEndCallback?.Invoke(RetStatus.Error, err); return; } if (suc != null) { BDebug.Log(suc); await UniTask.SwitchToMainThread(); onTaskEndCallback?.Invoke(RetStatus.Success, suc); return; } //3.生成差异列表 BDebug.Log("【版本控制】3.获取差异列表~", "red"); Queue <AssetItem> diffDownloadQueue = null; #region 生成差异文件 switch (updateMode) { case UpdateMode.Compare: { diffDownloadQueue = Compare(localAssetsInfoList, serverAssetsInfoList, platform); } break; case UpdateMode.Repair: case UpdateMode.CompareWithRepair: //CP 获取差异模式与Repair一致 { diffDownloadQueue = Repair(serverAssetsInfoList, platform); } break; } BDebug.Log($"【版本控制】 配置数量:{serverAssetsInfoList.Count} ,本地存在{serverAssetsInfoList.Count - diffDownloadQueue.Count},下载文件数量{diffDownloadQueue.Count}", "yellow"); #endregion //4.开始下载 #region 根据差异文件下载 BDebug.Log("【版本控制】4.下载资源~", "red"); { var failDownloadList = await DownloadAssets(serverUrl, localSaveAssetsPath, diffDownloadQueue, onDownloadProccess); if (failDownloadList.Count > 0) { onTaskEndCallback(RetStatus.Error, "部分资源未下载完毕!"); return; } } #endregion //5.写入配置到本地 #region 存储配置到本地 BDebug.Log("【版本控制】5.写入配置~", "red"); string localAssetInfoPath = ""; if (isDownloadSubPackageMode) { localAssetInfoPath = BResources.GetAssetsSubPackageInfoPath(BApplication.persistentDataPath, platform, subPackageName); } else { localAssetInfoPath = BResources.GetAssetsInfoPath(BApplication.persistentDataPath, platform); } //写入Asset.Info File.WriteAllText(localAssetInfoPath, serverAssetsContent); BDebug.Log($"【版本控制】写入{Path.GetFileName(localAssetInfoPath)} \n {serverAssetsContent}"); //写入Version.Info if (isDownloadSubPackageMode) { localVersionInfo.Platfrom = serverVersionInfo.Platfrom; //子包版本信息 localVersionInfo.SubPckMap[subPackageName] = serverVersionInfo.SubPckMap[subPackageName]; } else { localVersionInfo.Platfrom = serverVersionInfo.Platfrom; //全量包信息 localVersionInfo.Version = serverVersionInfo.Version; } var localAssetsVersionInfoPath = BResources.GetServerAssetsVersionInfoPath(localSaveAssetsPath, platform); File.WriteAllText(localAssetsVersionInfoPath, JsonMapper.ToJson(localVersionInfo)); BDebug.Log($"【版本控制】写入{Path.GetFileName(localAssetsVersionInfoPath)}"); #endregion // 6.删除过期资源 BDebug.Log("【版本控制】6.冗余资源检查~", "red"); if (!isDownloadSubPackageMode) { var artAssetsPath = IPath.Combine(localSavePlatformPath, BResources.ART_ASSET_ROOT_PATH); var persistentArtAssets = Directory.GetFiles(artAssetsPath, "*", SearchOption.AllDirectories); var replacePath = localSavePlatformPath + "/"; foreach (var assetPath in persistentArtAssets) { var localPath = assetPath.Replace(replacePath, "").Replace("\\", "/"); var ret = serverAssetsInfoList.FirstOrDefault((info) => info.LocalPath.Equals(localPath)); if (ret == null) { BDebug.Log("【版本控制】删除过期资源:" + localPath); File.Delete(assetPath); } } } // 7.资源校验文件 BDebug.Log("【版本控制】7.整包资源校验~", "red"); err = null; foreach (var serverAssetItem in serverAssetsInfoList) { var ret = BResources.IsExsitAssetWithCheckHash(platform, serverAssetItem.LocalPath, serverAssetItem.HashName); if (!ret) { if (string.IsNullOrEmpty(err)) { err = "资源不存在:"; } err += $"\n {serverAssetItem.LocalPath}"; } } //the end. BDebug.Log("【版本控制】end.完成~", "red"); await UniTask.SwitchToMainThread(); if (err == null) { onTaskEndCallback?.Invoke(RetStatus.Success, null); } else { onTaskEndCallback?.Invoke(RetStatus.Error, err); } }
/// <summary> /// 获取下载子包的数据 /// </summary> /// <returns>err, suc, server.info, local.info, </returns> public (string, string, List <AssetItem>, List <AssetItem>, string) GetDownloadSubPackageData(string serverUrl, string subPackageName, RuntimePlatform platform, AssetsVersionInfo serverVersionInfo, AssetsVersionInfo localVersionInfo) { //返回数据 string err = null; string suc = null; var serverAssetsInfoList = new List <AssetItem>(); var localAssetsInfoList = new List <AssetItem>(); var serverAssetsContent = ""; BDebug.Log("【版本控制】分包模式:" + subPackageName); //AssetInfo路径 //1.判断版本号 var ret = serverVersionInfo.SubPckMap.TryGetValue(subPackageName, out var serverSubPckVersion); if (!ret) { err = "【版本控制】服务器不存在子包:" + subPackageName; return(err, suc, null, null, null); } localVersionInfo.SubPckMap.TryGetValue(subPackageName, out var localSubPckVersion); if (serverSubPckVersion == localSubPckVersion) { suc = "【版本控制】分包版本一致,无需下载!"; // BDebug.Log(suc); return(err, suc, null, null, null); } //本地版本记录 if (!string.IsNullOrEmpty(localVersionInfo.Version) && !string.IsNullOrEmpty(localSubPckVersion)) { if (localVersionInfo.Version != localSubPckVersion) { BDebug.Log("【版本控制】分包资源大于 本地整包资源.请注意资源版本有可能不匹配!", "red"); } } //2.下载AssetInfo BDebug.Log($"【版本控制】分包下载模式! server:{serverSubPckVersion} local:{localSubPckVersion} ", "red"); { //服务器路径 var serverAssetInfosUrl = BResources.GetAssetsSubPackageInfoPath(serverUrl, platform, subPackageName); //下载服务器配置 (err, serverAssetsInfoList, serverAssetsContent) = LoadServerAssetInfo(serverAssetInfosUrl); } //1.加载本地SubPackage配置 localAssetsInfoList = LoadLocalSubPacakgeAssetInfo(platform, localVersionInfo); //2.加载本地asset.info var localAssetsInfo = this.LoadLocalAssetInfo(platform); localAssetsInfoList.AddRange(localAssetsInfo); //去重、排序 localAssetsInfoList = localAssetsInfoList.Distinct().ToList(); localAssetsInfoList.Sort((a, b) => { if (a.Id < b.Id) { return(-1); } else if (a.Id == b.Id) { return(0); } else { return(1); } }); //返回 return(err, suc, serverAssetsInfoList, localAssetsInfoList, serverAssetsContent); }
/// <summary> /// 文件转hash /// </summary> /// <param name="outputRootPath"></param> /// <param name="platform"></param> /// <param name="version"></param> /// <returns></returns> static public string GenServerHashAssets(string outputRootPath, RuntimePlatform platform, string version) { Debug.Log($"<color=red>------>生成服务器Hash文件:{BApplication.GetPlatformPath(platform)}</color>"); outputRootPath = IPath.ReplaceBackSlash(outputRootPath); //文件夹准备 var outputDir = IPath.Combine(outputRootPath, UPLOAD_FOLDER_SUFFIX, BApplication.GetPlatformPath(platform)); if (Directory.Exists(outputDir)) { Directory.Delete(outputDir, true); } Directory.CreateDirectory(outputDir); //获取资源的hash数据 var assetItemList = GetAssetItemList(outputRootPath, platform); foreach (var assetItem in assetItemList) { var localpath = IPath.Combine(outputRootPath, BApplication.GetPlatformPath(platform), assetItem.LocalPath); var copytoPath = IPath.Combine(outputDir, assetItem.HashName); File.Copy(localpath, copytoPath); } //服务器版本信息 var serverAssetsInfo = new AssetsVersionInfo(); //生成分包信息 //加载assetbundle配置 // var abConfigPath = string.Format("{0}/{1}", assetsRootPath, BResources.ASSET_CONFIG_PATH); // var abConfigLoader = new AssetbundleConfigLoder(); // abConfigLoader.Load(abConfigPath, null); var path = IPath.Combine(outputRootPath, BApplication.GetPlatformPath(platform), BResources.ASSETS_SUB_PACKAGE_CONFIG_PATH); if (File.Exists(path)) { var subpackageList = CsvSerializer.DeserializeFromString <List <SubPackageConfigItem> >(File.ReadAllText(path)); foreach (var subPackageConfigItem in subpackageList) { var subPackageItemList = new List <AssetItem>(); //美术资产 foreach (var id in subPackageConfigItem.ArtAssetsIdList) { //var assetbundleItem = abConfigLoader.AssetbundleItemList[id]; var serverAssetsItem = assetItemList.Find((item) => item.Id == id); subPackageItemList.Add(serverAssetsItem); if (serverAssetsItem == null) { Debug.LogError("不存在art asset:" + id); } } //脚本 foreach (var hcName in subPackageConfigItem.HotfixCodePathList) { var serverAssetsItem = assetItemList.Find((item) => item.LocalPath == hcName); subPackageItemList.Add(serverAssetsItem); if (serverAssetsItem == null) { Debug.LogError("不存在code asset:" + hcName); } } //表格 foreach (var tpName in subPackageConfigItem.TablePathList) { var serverAssetsItem = assetItemList.Find((item) => item.LocalPath == tpName); subPackageItemList.Add(serverAssetsItem); if (serverAssetsItem == null) { Debug.LogError("不存在table asset:" + tpName); } } //配置 foreach (var confName in subPackageConfigItem.ConfAndInfoList) { var serverAssetsItem = assetItemList.Find((item) => item.LocalPath == confName); subPackageItemList.Add(serverAssetsItem); if (serverAssetsItem == null) { Debug.LogError("不存在conf:" + confName); } } // subPackageItemList.Sort((a, b) => { if (a.Id < b.Id) { return(-1); } else { return(1); } }); //写入本地配置 var subPackageInfoPath = BResources.GetAssetsSubPackageInfoPath(IPath.Combine(outputRootPath, UPLOAD_FOLDER_SUFFIX), platform, subPackageConfigItem.PackageName); var configContent = CsvSerializer.SerializeToString(subPackageItemList); FileHelper.WriteAllText(subPackageInfoPath, configContent); Debug.Log("生成分包文件:" + Path.GetFileName(subPackageInfoPath)); //写入subPck - version serverAssetsInfo.SubPckMap[Path.GetFileName(subPackageInfoPath)] = version; } } //生成服务器AssetInfo var csv = CsvSerializer.SerializeToString(assetItemList); var configPath = IPath.Combine(outputDir, BResources.ASSETS_INFO_PATH); FileHelper.WriteAllText(configPath, csv); //生成服务器版本号 serverAssetsInfo.Platfrom = BApplication.GetPlatformPath(platform); serverAssetsInfo.Version = version; var json = JsonMapper.ToJson(serverAssetsInfo); configPath = IPath.Combine(outputDir, BResources.SERVER_ASSETS_VERSION_INFO_PATH); FileHelper.WriteAllText(configPath, json); return(outputDir); }