Example #1
0
        /// <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);
        }
Example #2
0
        /// <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);
            }
        }
Example #3
0
        /// <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);
        }