/// <summary>
        /// 打包资源
        /// </summary>
        public void BuildAssetBundle(string outputPath, RuntimePlatform platform)
        {
            //ab会先构建代码,提前构建,避免浪费时间
            var ret = PublishPipeLineCI.CheckCode();

            if (ret)
            {
                //生成Assetbundlebunle
                AssetBundleEditorToolsV2.GenAssetBundle(outputPath, platform);
                AssetDatabase.Refresh();
                Debug.Log("资源打包完毕");
            }
        }
        /// <summary>
        /// 加载所有assetbundle
        /// </summary>
        /// <returns></returns>
        static IEnumerator IE_LoadAll()
        {
            var outpath = BApplication.BDEditorCachePath + "/AssetBundle";

            if (!Directory.Exists(outpath))
            {
                Directory.CreateDirectory(outpath);
            }

            loadDataMap.Clear();
            //加载
            var allRuntimeAssets = BApplication.GetAllRuntimeAssetsPath();

            foreach (var asset in allRuntimeAssets)
            {
                var type = AssetBundleEditorToolsV2.GetMainAssetTypeAtPath(asset);
                if (type == null)
                {
                    Debug.LogError("无法获得资源类型:" + asset);
                    continue;
                }

                var idx         = asset.IndexOf(AssetBundleBuildingContext.RUNTIME_PATH, StringComparison.OrdinalIgnoreCase);
                var runtimePath = asset.Substring(idx + AssetBundleBuildingContext.RUNTIME_PATH.Length);
                runtimePath = runtimePath.Replace(Path.GetExtension(runtimePath), "");
                runtimePath = runtimePath.Replace("\\", "/");
                //Debug.Log("【LoadTest】:" + runtimePath);
                List <LoadTimeData> loadList = null;
                if (!loadDataMap.TryGetValue(type.FullName, out loadList))
                {
                    loadList = new List <LoadTimeData>();
                    loadDataMap[type.FullName] = loadList;
                }

                var loadData = new LoadTimeData();
                loadData.LoadPath = runtimePath;
                loadList.Add(loadData);
                //计时器
                Stopwatch sw = new Stopwatch();
                if (type == typeof(GameObject))
                {
                    //加载
                    sw.Start();
                    var obj = AssetBundleLoader.Load <GameObject>(runtimePath);
                    sw.Stop();
                    loadData.LoadTime = sw.ElapsedTicks;
                    //实例化
                    if (obj != null)
                    {
                        sw.Restart();
                        var gobj = GameObject.Instantiate(obj);
                        sw.Stop();
                        loadData.InstanceTime = sw.ElapsedTicks;
                        //UI
                        var rectTransform = gobj.GetComponentInChildren <RectTransform>();
                        if (rectTransform != null)
                        {
                            gobj.transform.SetParent(UI_ROOT, false);
                        }
                        else
                        {
                            gobj.transform.SetParent(SCENE_ROOT);
                        }

                        //抓屏 保存
                        var outpng = string.Format("{0}/{1}_ab.png", outpath, runtimePath.Replace("/", "_"));
                        yield return(null);

                        //渲染
                        GameView.Repaint();
                        GameView.Focus();

                        yield return(null);

                        //抓屏
                        //TODO 这里有时候能抓到 有时候抓不到
                        ScreenCapture.CaptureScreenshot(outpng);
                        //删除
                        GameObject.DestroyImmediate(gobj);
                    }
                    else
                    {
                        UnityEngine.Debug.LogError("【Prefab】加载失败:" + runtimePath);
                    }
                }
                else if (type == typeof(TextAsset))
                {
                    //测试打印AssetText资源
                    sw.Start();
                    var textAsset = AssetBundleLoader.Load <TextAsset>(runtimePath);
                    sw.Stop();
                    loadData.LoadTime = sw.ElapsedTicks;
                    if (!textAsset)
                    {
                        UnityEngine.Debug.LogError("【TextAsset】加载失败:" + runtimePath);
                    }
                    else
                    {
                        UnityEngine.Debug.Log(textAsset.text);
                    }
                }
                else if (type == typeof(Texture))
                {
                    sw.Start();
                    var tex = AssetBundleLoader.Load <Texture>(runtimePath);
                    sw.Stop();
                    loadData.LoadTime = sw.ElapsedTicks;
                    if (!tex)
                    {
                        UnityEngine.Debug.LogError("【Texture】加载失败:" + runtimePath);
                    }

                    break;
                }
                else if (type == typeof(Texture2D))
                {
                    sw.Start();
                    var tex = AssetBundleLoader.Load <Texture2D>(runtimePath);
                    sw.Stop();
                    loadData.LoadTime = sw.ElapsedTicks;
                    if (!tex)
                    {
                        UnityEngine.Debug.LogError("【Texture2D】加载失败:" + runtimePath);
                    }
                }
                else if (type == typeof(Sprite))
                {
                    sw.Start();
                    var sp = AssetBundleLoader.Load <Sprite>(runtimePath);
                    sw.Stop();
                    loadData.LoadTime = sw.ElapsedTicks;
                    if (!sp)
                    {
                        UnityEngine.Debug.LogError("【Sprite】加载失败:" + runtimePath);
                    }
                }
                else if (type == typeof(Material))
                {
                    sw.Start();
                    var mat = AssetBundleLoader.Load <Material>(runtimePath);
                    sw.Stop();
                    loadData.LoadTime = sw.ElapsedTicks;
                    if (!mat)
                    {
                        UnityEngine.Debug.LogError("【Material】加载失败:" + runtimePath);
                    }
                }
                else if (type == typeof(Shader))
                {
                    sw.Start();
                    var shader = AssetBundleLoader.Load <Shader>(runtimePath);
                    sw.Stop();
                    loadData.LoadTime = sw.ElapsedTicks;
                    if (!shader)
                    {
                        UnityEngine.Debug.LogError("【Shader】加载失败:" + runtimePath);
                    }
                }
                else if (type == typeof(AudioClip))
                {
                    sw.Start();
                    var ac = AssetBundleLoader.Load <AudioClip>(runtimePath);
                    sw.Stop();
                    loadData.LoadTime = sw.ElapsedTicks;
                    if (!ac)
                    {
                        UnityEngine.Debug.LogError("【AudioClip】加载失败:" + runtimePath);
                    }
                }
                else if (type == typeof(AnimationClip))
                {
                    sw.Start();
                    var anic = AssetBundleLoader.Load <AnimationClip>(runtimePath);
                    sw.Stop();
                    loadData.LoadTime = sw.ElapsedTicks;
                    if (!anic)
                    {
                        UnityEngine.Debug.LogError("【AnimationClip】加载失败:" + runtimePath);
                    }
                }
                else if (type == typeof(Mesh))
                {
                    sw.Start();
                    var mesh = AssetBundleLoader.Load <Mesh>(runtimePath);
                    sw.Stop();
                    loadData.LoadTime = sw.ElapsedTicks;
                    if (!mesh)
                    {
                        UnityEngine.Debug.LogError("【Mesh】加载失败:" + runtimePath);
                    }
                }
                else if (type == typeof(Font))
                {
                    sw.Start();

                    var font = AssetBundleLoader.Load <Font>(runtimePath);

                    sw.Stop();
                    loadData.LoadTime = sw.ElapsedTicks;
                    if (!font)
                    {
                        UnityEngine.Debug.LogError("【Font】加载失败:" + runtimePath);
                    }
                }
                else if (type == typeof(SpriteAtlas))
                {
                    sw.Start();
                    var sa = AssetBundleLoader.Load <SpriteAtlas>(runtimePath);
                    sw.Stop();
                    if (!sa)
                    {
                        UnityEngine.Debug.LogError("【SpriteAtlas】加载失败:" + runtimePath);
                    }

                    loadData.LoadTime = sw.ElapsedTicks;
                }
                else if (type == typeof(ShaderVariantCollection))
                {
                    sw.Start();
                    var svc = AssetBundleLoader.Load <ShaderVariantCollection>(runtimePath);
                    svc?.WarmUp();
                    sw.Stop();
                    if (!svc)
                    {
                        UnityEngine.Debug.LogError("【ShaderVariantCollection】加载失败:" + runtimePath);
                    }

                    loadData.LoadTime = sw.ElapsedTicks;
                }
                else if (type == typeof(AnimatorController))
                {
                    sw.Start();
                    var aniCtrl = AssetBundleLoader.Load <AnimatorController>(runtimePath);
                    sw.Stop();
                    if (!aniCtrl)
                    {
                        UnityEngine.Debug.LogError("【AnimatorController】加载失败:" + runtimePath);
                    }

                    loadData.LoadTime = sw.ElapsedTicks;
                }
                else
                {
                    sw.Start();
                    var gobj = AssetBundleLoader.Load <Object>(runtimePath);
                    sw.Stop();
                    if (!gobj)
                    {
                        UnityEngine.Debug.LogError("【Object】加载失败:" + runtimePath);
                    }

                    UnityEngine.Debug.LogError("待编写测试! -" + type.FullName);
                }

                //打印

                Debug.LogFormat("<color=yellow>{0}</color> <color=green>【加载】:<color=yellow>{1}ms</color>;【初始化】:<color=yellow>{2}ms</color> </color>", loadData.LoadPath, loadData.LoadTime / 10000f, loadData.InstanceTime / 10000f);
                yield return(null);
            }

            yield return(null);

            foreach (var item in loadDataMap)
            {
                Debug.Log("<color=red>【" + item.Key + "】</color>");
                foreach (var ld in item.Value)
                {
                    Debug.LogFormat(
                        "<color=yellow>{0}</color> <color=green>【加载】:<color=yellow>{1}ms</color>;【初始化】:<color=yellow>{2}ms</color> </color>",
                        ld.LoadPath, ld.LoadTime / 10000f, ld.InstanceTime / 10000f);
                }
            }

            yield return(null);

            EditorUtility.RevealInFinder(outpath);
        }
Beispiel #3
0
        /// <summary>
        /// 开始构建AB
        /// </summary>
        public void StartBuildAssetBundle(BuildTarget buildTarget)
        {
            //-----------------------开始打包AssetBundle逻辑---------------------------
            Debug.Log("【BuildAssetbundle】执行Build...");
            //设置编辑器状态
            BDEditorApplication.EditorStatus = BDFrameworkEditorStatus.BuildAssetBundle;
            var    platform           = BApplication.GetRuntimePlatform(buildTarget);
            var    platformOutputPath = IPath.Combine(BuildParams.OutputPath, BApplication.GetPlatformPath(platform));
            string abOutputPath       = IPath.Combine(platformOutputPath, BResources.ART_ASSET_ROOT_PATH);

            //--------------------------------开始打包----------------------------------
            //1.打包
            Debug.Log("<color=green>----->1.进入打包逻辑</color>");
            //整理abname
            this.MergeABName(BuildingAssetInfos);
            //对比差异文件
            var changedAssetsInfo = GetChangedAssets(BuildingAssetInfos, buildTarget);
            //生成artconfig
            var assetbundleItemList = this.GenAssetBundleConfig(BuildingAssetInfos, BuildParams, platform);

            //打包
            AssetDatabase.StartAssetEditing(); //禁止自动导入
            {
                this.BuildAssetBundle(assetbundleItemList, changedAssetsInfo, BuildParams, platform);
            }
            AssetDatabase.StopAssetEditing(); //恢复自动导入


            //2.清理
            Debug.Log("<color=green>----->2.清理旧ab</color>");
            //移除所有的ab
            RemoveAllAssetbundleName();
            //删除本地没有的资源
            var allABList = Directory.GetFiles(abOutputPath, "*", SearchOption.AllDirectories).Where((p) => string.IsNullOrEmpty(Path.GetExtension(p)));

            foreach (var abpath in allABList)
            {
                var abname = Path.GetFileName(abpath);
                var ret    = assetbundleItemList.FirstOrDefault((abdata) => abdata.AssetBundlePath == abname);
                if (ret == null)
                {
                    //
                    File.Delete(abpath);
                    File.Delete(abpath + ".manifest");
                    //
                    var path = AssetDatabase.GUIDToAssetPath(abname);
                    Debug.Log("【删除旧ab:】" + abname + "  -  " + path);
                }
            }



            //3.BuildInfo配置处理
            Debug.Log("<color=green>----->3.BuildInfo相关生成</color>");
            //设置ab的hash
            foreach (var abi in assetbundleItemList)
            {
                if (string.IsNullOrEmpty(abi.AssetBundlePath))
                {
                    continue;
                }

                var abpath = IPath.Combine(platformOutputPath, BResources.ART_ASSET_ROOT_PATH, abi.AssetBundlePath);
                var hash   = FileHelper.GetMurmurHash3(abpath);
                abi.Hash = hash;
            }

            //获取上一次打包的数据,跟这次打包数据合并
            var configPath = IPath.Combine(platformOutputPath, BResources.ART_ASSET_CONFIG_PATH);

            if (File.Exists(configPath))
            {
                var lastAssetbundleItemList = CsvSerializer.DeserializeFromString <List <AssetBundleItem> >(File.ReadAllText(configPath));
                foreach (var newABI in assetbundleItemList)
                {
                    if (string.IsNullOrEmpty(newABI.AssetBundlePath))
                    {
                        continue;
                    }

                    // //判断是否在当前打包列表中
                    // var ret = changedAssetsInfo.AssetDataMaps.Values.FirstOrDefault((a) => a.ABName.Equals(newABI.AssetBundlePath, StringComparison.OrdinalIgnoreCase));

                    var lastABI = lastAssetbundleItemList.FirstOrDefault((last) =>
                                                                         newABI.AssetBundlePath.Equals(last.AssetBundlePath, StringComparison.OrdinalIgnoreCase)); //AB名相等
                    //&& newABI.Hash == last.Hash); //hash相等
                    //没重新打包,则用上一次的mix信息
                    if (lastABI != null && lastABI.Hash == newABI.Hash)
                    {
                        newABI.Mix = lastABI.Mix;
                    }
                    //否则mix = 0
                }
            }

            //保存artconfig.info
            var csv = CsvSerializer.SerializeToString(assetbundleItemList);

            FileHelper.WriteAllText(configPath, csv);


            //保存BuildInfo配置
            var buildinfoPath = IPath.Combine(platformOutputPath, BResources.EDITOR_ART_ASSET_BUILD_INFO_PATH);
            //缓存buildinfo
            var json = JsonMapper.ToJson(BuildingAssetInfos, true);

            FileHelper.WriteAllText(buildinfoPath, json);


            //4.备份Artifacts
            //this.BackupArtifacts(buildTarget);

            //5.检测本地的Manifest和构建预期对比
            Debug.Log("<color=green>----->5.校验AB依赖</color>");
            var abRootPath       = IPath.Combine(BuildParams.OutputPath, BApplication.GetPlatformPath(platform), BResources.ART_ASSET_ROOT_PATH);
            var previewABUnitMap = BuildingAssetInfos.PreviewAssetbundleUnit();
            var manifestList     = Directory.GetFiles(abRootPath, "*.manifest", SearchOption.AllDirectories);

            //解析 manifestBuildParams.OutputPath
            for (int i = 0; i < manifestList.Length; i++)
            {
                var manifest = manifestList[i].Replace("\\", "/");


                if (manifest.Equals(abRootPath + ".manifest"))
                {
                    continue;
                }

                var           lines = File.ReadLines(manifest);
                List <string> manifestDependList = new List <string>();
                bool          isStartRead        = false;
                foreach (var line in lines)
                {
                    if (!isStartRead && line.Equals("Assets:"))
                    {
                        isStartRead = true;
                    }
                    else if (line.Contains("Dependencies:"))
                    {
                        break;
                    }
                    else if (isStartRead)
                    {
                        var file = line.Replace("- ", "");
                        manifestDependList.Add(file.ToLower());
                    }
                }

                //对比依赖
                var abname = Path.GetFileNameWithoutExtension(manifest);
                if (abname.Equals(BResources.ART_ASSET_ROOT_PATH, StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                previewABUnitMap.TryGetValue(abname, out var previewABDependList);
                if (previewABDependList == null)
                {
                    Debug.LogError("【AssetbundleV2-验证】本地ab的配置不不存在:" + abname);
                    Debug.LogError("path:" + AssetDatabase.GUIDToAssetPath(abname));
                }
                else
                {
                    //求差集
                    var except = manifestDependList.Except(previewABDependList);
                    if (except.Count() != 0)
                    {
                        var local   = JsonMapper.ToJson(manifestDependList, true);
                        var preview = JsonMapper.ToJson(previewABDependList, true);
                        Debug.LogError($"【AssetbundleV2-验证】本地AssetBundle依赖与预期不符:\n 本地:{local} \n 预期:{preview}");
                    }
                }
            }


            //6.资源混淆
            Debug.Log("<color=green>----->6.混淆AB</color>");
            if (BDEditorApplication.BDFrameworkEditorSetting.BuildAssetBundleSetting.IsEnableObfuscation)
            {
                AssetBundleEditorToolsV2.MixAssetBundle(BuildParams.OutputPath, platform);
            }


            //恢复编辑器状态
            BDEditorApplication.EditorStatus = BDFrameworkEditorStatus.Idle;
            //BD生命周期触发
            BDFrameworkPipelineHelper.OnEndBuildAssetBundle(this);


            //GenAssetBundleItemCacheList = abConfigList.ToList();
        }
        /// <summary>
        /// 最新包
        /// </summary>
        void OnGUI_TestAssetBundle()
        {
            GUILayout.BeginVertical();
            {
                GUILayout.Label("构建资源:", EditorGUIHelper.LabelH4);
                GUILayout.BeginHorizontal();
                {
                    if (GUILayout.Button("收集Keyword[Shader Feature]", GUILayout.Width(200), GUILayout.Height(25)))
                    {
                        ShaderCollection.CollectShaderVariant();
                    }

                    if (GUILayout.Button("打包Shader测试", GUILayout.Width(120), GUILayout.Height(25)))
                    {
                        ShaderCollection.BuildShadersAssetBundle();
                    }
                }
                GUILayout.EndHorizontal();

                if (GUILayout.Button("编辑AssetBundle颗粒度", GUILayout.Height(25)))
                {
                    var win = GetWindow <AssetGraphEditorWindow>();
                    win.OpenGraph("Assets/AssetGraph/BResourceAssetBundleConfig.asset");
                }


                GUILayout.Space(5);
                //遍历支持平台
                foreach (var platform in BApplication.SupportPlatform)
                {
                    GUILayout.BeginHorizontal();
                    {
                        GUILayout.Label(BApplication.GetPlatformPath(platform), GUILayout.Width(80));

                        GUILayout.Space(20);

                        GUI.color = Color.green;

                        if (GUILayout.Button("Build", GUILayout.Width(80)))
                        {
                            var ret = EditorUtility.DisplayDialog("提示", "是否要构建AssetBundle? \n平台:" + BApplication.GetPlatformPath(platform), "Ok", "Cancel");
                            if (ret)
                            {
                                //开始打包
                                BuildAssetBundle(BApplication.DevOpsPublishAssetsPath, platform);
                            }
                        }

                        if (GUILayout.Button("混淆AB", GUILayout.Width(80)))
                        {
                            var ret = EditorUtility.DisplayDialog("提示", "是否要混淆AssetBundle? \n平台:" + BApplication.GetPlatformPath(platform), "Ok", "Cancel");
                            if (ret)
                            {
                                AssetBundleEditorToolsV2.MixAssetBundle(BApplication.DevOpsPublishAssetsPath, platform);
                            }
                        }

                        GUI.color = GUI.backgroundColor;
                    }
                    GUILayout.EndHorizontal();
                }


                GUILayout.Space(10); //();
                GUILayout.Label("资源验证:", EditorGUIHelper.LabelH4);
                //加载ab
                GUILayout.BeginHorizontal();
                {
                    GUILayout.Label("AssetBundle验证: DevOps目录", EditorGUIHelper.GetFontStyle(Color.white, 12));
                    if (GUILayout.Button("Play", GUILayout.Width(50), GUILayout.Height(20)))
                    {
                        AssetBundleEditorToolsV2CheckAssetbundle.TestLoadAssetbundleRuntime();
                    }
                }
                GUILayout.EndHorizontal();
                // GUILayout.Space(5); //();
                // //加载ab异步
                // GUILayout.BeginHorizontal();
                // {
                //     GUILayout.Label("AssetBundle验证: 加载所有-Async (DevOps目录)", EditorGUIHelper.GetFontStyle(Color.white, 12));
                //     if (GUILayout.Button("Play", GUILayout.Width(50), GUILayout.Height(20)))
                //     {
                //         AssetBundleEditorToolsV2CheckAssetbundle.TestLoadAssetbundleRuntimeAsync();
                //     }
                // }
                // GUILayout.EndHorizontal();
            }
            GUILayout.EndVertical();
        }
        /// <summary>
        /// 生成BuildInfo信息
        /// </summary>
        public bool GenBuildInfo()
        {
            //初始化数据
            this.AssetTypeList     = new List <string>();
            this.BuildAssetsInfo   = new BuildAssetsInfo();
            this.RuntimeAssetsList = GetRuntimeAssetsInfo();

            //
            var sw = new Stopwatch();

            sw.Start();

            BuildAssetsInfo.Time = DateTime.Now.ToShortDateString();
            int id = 0;

            //搜集所有的依赖
            foreach (var mainAsset in this.RuntimeAssetsList)
            {
                //这里会包含主资源
                var dependAssetPathList = GetDependAssetList(mainAsset.importFrom);

                //获取依赖信息 并加入buildinfo
                foreach (var dependPath in dependAssetPathList)
                {
                    //防止重复
                    if (BuildAssetsInfo.AssetDataMaps.ContainsKey(dependPath))
                    {
                        continue;
                    }

                    //判断资源类型
                    var type = AssetBundleEditorToolsV2.GetMainAssetTypeAtPath(dependPath);
                    if (type == null)
                    {
                        Debug.LogError("获取资源类型失败:" + dependPath);
                        continue;
                    }

                    //构建资源类型
                    var assetData = new BuildAssetsInfo.BuildAssetData();
                    assetData.Id     = id;
                    assetData.Hash   = this.GetHashFromAssets(dependPath);
                    assetData.ABName = dependPath;
                    var idx = AssetTypeList.FindIndex((a) => a == type.FullName);
                    if (idx == -1)
                    {
                        AssetTypeList.Add(type.FullName);
                        idx = AssetTypeList.Count - 1;
                    }

                    assetData.Type = idx;
                    //获取依赖
                    var dependeAssetList = this.GetDependAssetList(dependPath);
                    assetData.DependAssetList.AddRange(dependeAssetList);
                    //添加
                    BuildAssetsInfo.AssetDataMaps[dependPath] = assetData;
                    id++;
                }
            }

            //TODO AB依赖关系纠正
            /// 已知Unity,bug/设计缺陷:
            ///   1.依赖接口,中会携带自己
            ///   2.如若a.png、b.png 依赖 c.atlas,则abc依赖都会是:a.png 、b.png 、 a.atlas
            foreach (var asset in BuildAssetsInfo.AssetDataMaps)
            {
                //依赖中不包含自己
                asset.Value.DependAssetList.Remove(asset.Value.ABName);
            }


            //获取依赖
            this.DependAssetList = this.GetDependAssetsinfo();
            //---------------------------------------end---------------------------------------------------------

            //检查
            foreach (var ar in this.RuntimeAssetsList)
            {
                if (!BuildAssetsInfo.AssetDataMaps.ContainsKey(ar.importFrom))
                {
                    Debug.LogError("AssetDataMaps遗漏资源:" + ar.importFrom);
                }
            }

            Debug.LogFormat("【GenBuildInfo】耗时:{0}ms.", sw.ElapsedMilliseconds);
            //检测构造的数据
            var count = this.RuntimeAssetsList.Count + this.DependAssetList.Count;

            if (BuildAssetsInfo.AssetDataMaps.Count != count)
            {
                Debug.LogErrorFormat("【初始化框架资源环境】出错! buildinfo:{0} output:{1}", BuildAssetsInfo.AssetDataMaps.Count, count);

                var tmpBuildAssetsInfo = BuildAssetsInfo.Clone();
                foreach (var ra in this.RuntimeAssetsList)
                {
                    tmpBuildAssetsInfo.AssetDataMaps.Remove(ra.importFrom);
                }

                foreach (var drf in this.DependAssetList)
                {
                    tmpBuildAssetsInfo.AssetDataMaps.Remove(drf.importFrom);
                }

                Debug.Log(JsonMapper.ToJson(tmpBuildAssetsInfo.AssetDataMaps, true));

                return(false);
            }

            return(true);
        }