Beispiel #1
0
 public static void AddAsset(string filePath, AssetGroup asset_)
 {
     //if (m_path2asset.ContainsKey(filePath))
     //{
     //    Debug.Assert(asset_ != m_path2asset[filePath]);
     //    return;
     //}
     m_path2asset[filePath] = asset_;
 }
Beispiel #2
0
        //-------∽-★-∽------∽-★-∽--------∽-★-∽公共打包项∽-★-∽--------∽-★-∽------∽-★-∽--------//

        static AssetGroup GetShareAsset_Font()
        {
            AssetGroup assetInfo = new AssetGroup();

            assetInfo.name     = "font"; //"font.j";
            assetInfo.bundleId = BUNDLE_ID.FONT;
            assetInfo.files    = new List <string> {
                "Assets/Resources/GUI/cn/font/DroidSansFallback.ttf",
                "Assets/Resources/GUI/cn/font/FontMaterial.mat"
            };

            return(assetInfo);
        }
Beispiel #3
0
        static BundleGenInfo GetShareBundle()
        {
            AssetGroup[] assetInfos = new AssetGroup[]
            {
                GetShareAsset_Font(),
                GetShareAsset_Shader(),
            };

            BundleGenInfo genInfo = new BundleGenInfo();

            genInfo.bundleName = "share";
            genInfo.combineNum = 1;
            genInfo.assets.AddRange(assetInfos);

            return(genInfo);
        }
Beispiel #4
0
        static AssetGroup GetShareAsset_Shader()
        {
            var allShaderFiles = new List <string>();

            string[] suffixs = new[] { ".shader" };
            BundleUtility.CollectPathWithSuffix("Assets/RawData/Shaders/", suffixs, allShaderFiles, null);
            BundleUtility.CollectPathWithSuffix("Assets/Resources/Start/", suffixs, allShaderFiles, null);
            BundleUtility.CollectPathWithSuffix("Assets/ShaderForGame/", suffixs, allShaderFiles, null);

            AssetGroup assetInfo = new AssetGroup();

            assetInfo.name     = "shader";//"shader.j";
            assetInfo.bundleId = BUNDLE_ID.SHADER;
            assetInfo.files    = allShaderFiles;

            return(assetInfo);
        }
Beispiel #5
0
        //-------∽-★-∽------∽-★-∽--------∽-★-∽数据管理∽-★-∽--------∽-★-∽------∽-★-∽--------//

        /// <summary>
        /// 目前只用于顶级文件
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public static AssetGroup CreateAsset(string filePath)
        {
            if (m_path2asset.ContainsKey(filePath))
            {
                return(m_path2asset[filePath]);
            }

            string name;
            string path;

            BundleUtility.AnalyzeBundlePath(filePath, out path, out name);  //path->Resources/GUI/cn/Prefab, name->Canvas_Account

            AssetGroup assetInfo = new AssetGroup();

            // Assets/Resources/GUI/cn/Prefab/Canvas_Account.prefab -> Resources/GUI/cn/Prefab/Canvas_Account
            assetInfo.name    = BundleUtility.Utf8toAscii(String.Format("{0}/{1}", path, name)); //为什么要转为asc码?
            assetInfo.isPatch = false;
            assetInfo.files.Add(filePath);

            m_path2asset[filePath] = assetInfo;

            return(assetInfo);
        }
Beispiel #6
0
        public override void Collect(BundleGenInfo genInfo_)
        {
            string bundleName = genInfo_.bundleName;

            HashSet <string> topFileHash = new HashSet <string>();

            foreach (PathInfo pathInfo in genInfo_.pathInfos)
            {
                //顶级文件列表
                List <string> topFiles = new List <string>();
                //递归收集所有文件
                BundleUtility.CollectPathWithSuffix(pathInfo.path, pathInfo.suffixs, topFiles, pathInfo.exclude);
                //按名称排序
                topFiles.Sort();

                int bundleId = 0;
                int curIdx   = 0;
                while (curIdx < topFiles.Count)
                {
                    string     name  = bundleName + "_" + bundleId; //gui_0
                    AssetGroup asset = new AssetGroup();
                    asset.name      = name;
                    asset.isPatch   = false;
                    asset.isTopFile = true;

                    //合并
                    for (int i = 0; i < pathInfo.combineNum && curIdx < topFiles.Count; ++i, ++curIdx)
                    {
                        asset.files.Add(topFiles[curIdx]);
                        topFileHash.Add(topFiles[curIdx]);

                        BundleBuilder.AddAsset(topFiles[curIdx], asset);    //关联文件路径与BundleAsset
                    }

                    bundleId++;
                    genInfo_.assets.Add(asset);
                }
            }


            //收集依赖
            var asset2dpPathSet = new Dictionary <AssetGroup, HashSet <string> >();    //A的dpPathSet与B的此时可能会有重复依赖项

            foreach (AssetGroup asset in genInfo_.assets)
            {
                var __dpPathSet = new HashSet <string>();
                asset2dpPathSet[asset] = __dpPathSet;

                foreach (string path in asset.files)
                {
                    BundleUtility.CollectDepends(path, __dpPathSet);
                }

                //排除顶级依赖
                List <string> excludes = new List <string>();
                foreach (string path in __dpPathSet)
                {
                    if (topFileHash.Contains(path))    //这个依赖是顶级文件
                    {
                        excludes.Add(path);
                        //如果有依赖项是顶级文件,便直接添加到asset的depends中, 这些文件不视为外部依赖
                        AssetGroup topAsset = BundleBuilder.CreateAsset(path);
                        if (!asset.dpAssets.Contains(topAsset))
                        {
                            asset.dpAssets.Add(topAsset);
                        }
                    }
                }

                foreach (string path in excludes)   //从pathHash移除掉
                {
                    __dpPathSet.Remove(path);
                }
            }

            // 统计一个dependPath被包含到多少个Asset里
            var dpPath2assetSet = new Dictionary <string, HashSet <AssetGroup> >();

            foreach (var kvp in asset2dpPathSet)
            {
                AssetGroup       asset       = kvp.Key;
                HashSet <string> __dpPathSet = kvp.Value;
                foreach (string dpPath in __dpPathSet)
                {
                    HashSet <AssetGroup> assetHash;
                    if (!dpPath2assetSet.TryGetValue(dpPath, out assetHash))
                    {
                        assetHash = new HashSet <AssetGroup>();
                        dpPath2assetSet[dpPath] = assetHash;
                    }
                    assetHash.Add(asset);         //dpPath -> {AssetGroup, ...}
                }
            }

            List <string> toDelPaths = new List <string>();

            //只被一个文件依赖, 和此文件一起打包
            foreach (var kvp in dpPath2assetSet)
            {
                string dpPath = kvp.Key;
                HashSet <AssetGroup> assetHash = kvp.Value;
                if (assetHash.Count <= 1) //排查出只有一个引用的依赖
                {
                    AssetGroup       parentAsset = assetHash.First();
                    HashSet <string> __dpPathSet = asset2dpPathSet[parentAsset];
                    __dpPathSet.Remove(dpPath);      //从引用者的dpPathHash里面移除, 从而不属于公共依赖

                    toDelPaths.Add(dpPath);
                }
            }

            //dpPath2assetSet里只保留引用数>1的路径
            foreach (string path in toDelPaths)
            {
                dpPath2assetSet.Remove(path);
            }

            //对所有依赖进行排序
            List <string> mainDpPaths = new List <string>();

            mainDpPaths.AddRange(dpPath2assetSet.Keys);
            mainDpPaths.Sort((r, l) =>
            {
                if (dpPath2assetSet[r].Count != dpPath2assetSet[l].Count)
                {
                    //优先按依赖数量排序
                    return(dpPath2assetSet[l].Count - dpPath2assetSet[r].Count);
                }
                return(l.CompareTo(r));
            });

            //依赖总表
            HashSet <string> mainDpPathSet = new HashSet <string>();

            foreach (string path in mainDpPaths)
            {
                mainDpPathSet.Add(path);
            }


            HashSet <string> tmpDpPathSet = new HashSet <string>();
            List <string>    tmpDpPaths   = new List <string>();

            int index = 0;

            while (index < mainDpPaths.Count)
            {
                if (!mainDpPathSet.Contains(mainDpPaths[index]))
                {
                    //已经处理过
                    index++;
                    continue;
                }

                //50个依赖文件->dpPaths
                int           combineCnt = 50; //一个包的依赖文件个数
                List <string> dpFiles    = new List <string>();
                while (dpFiles.Count < combineCnt && index < mainDpPaths.Count)
                {
                    string path = mainDpPaths[index];
                    if (mainDpPathSet.Contains(path))
                    {
                        //还没处理过
                        mainDpPathSet.Remove(path);
                        dpFiles.Add(path);
                    }
                    index++;
                }

                //此时dpFiles有50个依赖文件

                bool hasMore = true;
                while (hasMore)
                {
                    hasMore = false;

                    tmpDpPaths.Clear();
                    tmpDpPaths.AddRange(dpFiles);

                    tmpDpPathSet.Clear();
                    BundleUtility.CollectDepends(tmpDpPaths.ToArray(), tmpDpPathSet); //收集这个依赖列表的所有依赖项

                    foreach (string path in tmpDpPathSet)
                    {
                        if (mainDpPathSet.Contains(path))
                        {
                            //次依赖在总表里,收集到本次列表里
                            mainDpPathSet.Remove(path);
                            dpFiles.Add(path);

                            hasMore = true;
                        }
                    }


                    //查找剩下全部依赖
                    tmpDpPaths.Clear();
                    tmpDpPaths.AddRange(mainDpPathSet);
                    foreach (string path in tmpDpPaths)
                    {
                        if (mainDpPathSet.Contains(path))
                        {
                            tmpDpPathSet.Clear();
                            BundleUtility.CollectDepends(tmpDpPaths.ToArray(), tmpDpPathSet); //收集剩下的全部依赖的所有依赖项

                            bool packed = false;
                            foreach (string dpPath in tmpDpPathSet)
                            {
                                if (dpFiles.Contains(dpPath))
                                {
                                    //如果这些依赖在这次的收集列表里, 也收集进来
                                    dpFiles.Add(path);
                                    mainDpPathSet.Remove(path);

                                    hasMore = true;
                                    packed  = true;
                                    break;
                                }
                            }

                            if (packed)
                            {
                                foreach (var dpPath in tmpDpPathSet)
                                {
                                    if (mainDpPathSet.Contains(dpPath))
                                    {
                                        mainDpPathSet.Remove(dpPath);
                                        //所有依赖里面在总表的都添加到这次的收集
                                        dpFiles.Add(dpPath);
                                    }
                                }
                            }
                        }
                    }
                }

                if (dpFiles.Count > 0)
                {
                }
            }
        }
Beispiel #7
0
        public override void Collect(BundleGenInfo genInfo_)
        {
            string bundleName = genInfo_.bundleName;

            //顶级文件列表
            List <string> topFiles = new List <string>();

            foreach (var pathInfo in genInfo_.pathInfos)
            {
                BundleUtility.CollectPathWithSuffix(pathInfo.path, pathInfo.suffixs, topFiles, pathInfo.exclude);    //递归收集所有文件
            }
            //按名称排序
            topFiles.Sort();


            foreach (string path in topFiles)
            {
                AssetGroup assetInfo = BundleBuilder.CreateAsset(path);
                assetInfo.isTopFile = true;   //是顶级文件
                genInfo_.assets.Add(assetInfo);
            }

            //收集依赖
            var asset2dpPathSet = new Dictionary <AssetGroup, HashSet <string> >();

            foreach (AssetGroup asset in genInfo_.assets)
            {
                HashSet <string> dpPathSet = new HashSet <string>();
                asset2dpPathSet[asset] = dpPathSet;

                foreach (string filePath in asset.files)     //到这里的files应该只有一个文件,之后会添加
                {
                    BundleUtility.CollectDepends(filePath, dpPathSet);
                }

                //排除顶级依赖
                List <string> excludes = new List <string>();
                foreach (string path in dpPathSet)
                {
                    if (topFiles.Contains(path))    //这个依赖是顶级文件
                    {
                        excludes.Add(path);
                        //如果有依赖项是顶级文件,便直接添加到asset的depends中, 这些文件不视为外部依赖
                        asset.dpAssets.Add(BundleBuilder.CreateAsset(path));
                    }
                }

                foreach (string path in excludes)   //从pathHash移除掉
                {
                    dpPathSet.Remove(path);
                }
            }

            // 统计一个dependPath被包含到多少个Asset里
            var dpPath2assetSet = new Dictionary <string, HashSet <AssetGroup> >();

            foreach (var kvp in asset2dpPathSet)
            {
                AssetGroup       asset     = kvp.Key;
                HashSet <string> dpPathSet = kvp.Value;
                foreach (string dpPath in dpPathSet)
                {
                    HashSet <AssetGroup> assetHash;
                    if (!dpPath2assetSet.TryGetValue(dpPath, out assetHash))
                    {
                        assetHash = new HashSet <AssetGroup>();
                        dpPath2assetSet[dpPath] = assetHash;
                    }
                    assetHash.Add(asset);         //dpPath -> {assetInfo, ...}
                }
            }

            List <string> toDelPath = new List <string>();

            // 只被一个文件依赖的 就和这个文件打包在一起,不再区分
            foreach (var kvp in dpPath2assetSet)
            {
                string dpPath = kvp.Key;
                HashSet <AssetGroup> assetHash = kvp.Value;
                if (assetHash.Count <= 1) //排查出只有一个引用的依赖
                {
                    AssetGroup       parentAsset = assetHash.First();
                    HashSet <string> dpPathSet   = asset2dpPathSet[parentAsset];
                    dpPathSet.Remove(dpPath);      //从引用者的dpPathHash里面移除, 从而不属于公共依赖

                    toDelPath.Add(dpPath);
                }
            }

            //dpPath2assetSet里只保留引用数>1的路径
            foreach (string path in toDelPath)
            {
                dpPath2assetSet.Remove(path);
            }



            //建立无向图(所有依赖的连通图) { {A(a,b,c), B(a,d,e) } -> { a(b,c,d,e), b(c,a), c(a,b), d(a,e), e(a,d) }
            var path2node = new Dictionary <string, GraphNode>();

            foreach (var kvp in asset2dpPathSet)
            {
                AssetGroup       asset     = kvp.Key;
                HashSet <string> dpPathSet = kvp.Value;   //被同一个资源引用的依赖列表
                foreach (string dpPath in dpPathSet)
                {
                    GraphNode dpNode;
                    if (!path2node.TryGetValue(dpPath, out dpNode))  //为所有依赖创建节点
                    {
                        dpNode            = new GraphNode();
                        dpNode.path       = dpPath;
                        path2node[dpPath] = dpNode;
                    }

                    foreach (string dpPath2 in dpPathSet)
                    {
                        if (dpPath2 == dpPath)
                        {
                            continue;
                        }

                        GraphNode dpNode2;
                        if (path2node.TryGetValue(dpPath2, out dpNode2))
                        {
                            //互相把自己添加到对方的edges
                            dpNode2.edges.Add(dpNode);
                            dpNode.edges.Add(dpNode2);
                        }
                    }
                }
            }

            //创建节点块(把所有连通的依赖独立出来一块) { (a,b,c,d,e), (...) }
            var nodeSets = new List <HashSet <GraphNode> >();

            foreach (var kvp in path2node)
            {
                GraphNode node = kvp.Value;
                if (!node.visited)
                {
                    HashSet <GraphNode> nodeSet = new HashSet <GraphNode>();
                    VisitNode(node, nodeSet);
                    nodeSets.Add(nodeSet);
                }
            }


            int idx = 0;

            foreach (var nodeSet in nodeSets)
            {
                AssetGroup dpAsset   = new AssetGroup();
                string     dpBdlName = Path.Combine("depends", string.Format("{0}_{1}", bundleName, idx)); //depends/gui_0
                dpAsset.name      = FileUtility.FomatPath(dpBdlName);
                dpAsset.isTopFile = false;

                foreach (GraphNode node in nodeSet)
                {
                    dpAsset.files.Add(node.path);
                }


                //如果顶级文件的依赖项里有依赖这个块的其中一个文件,便把这个块的包作为顶级文件的依赖项
                foreach (var kvp in asset2dpPathSet)
                {
                    AssetGroup       asset     = kvp.Key;
                    HashSet <string> dpPathSet = kvp.Value;

                    foreach (string dpPath in dpAsset.files)
                    {
                        if (dpPathSet.Contains(dpPath))
                        {
                            asset.dpAssets.Add(dpAsset);
                            break;
                        }
                    }
                }

                genInfo_.dpAssets.Add(dpAsset);      //添加到总依赖列表
                ++idx;
            }
        }
Beispiel #8
0
        /// <summary>
        /// 根据单个生成信息打包
        /// </summary>
        /// <param name="genInfo"></param>
        /// <param name="shareBuilds_">公共打包项</param>
        /// <param name="needBuild">是否需要build</param>
        /// <returns></returns>
        static List <AssetBundleBuild> BuildBundle(BundleGenInfo genInfo, AssetBundleBuild[] shareBuilds_, bool needBuild)
        {
            //先排个序
            genInfo.assets.Sort((l, r) =>
            {
                return(l.name.CompareTo(r.name));
            });

            List <AssetBundleBuild> bundleBuilds = new List <AssetBundleBuild>();

            if (shareBuilds_ != null) //公共打包项
            {
                bundleBuilds.AddRange(shareBuilds_);
            }

            //建立依赖的BundleBuild
            foreach (var dpAsset in genInfo.dpAssets)
            {
                dpAsset.name = BundleUtility.GetBundleOutputName(dpAsset.name);     //重新定义包名

                AssetBundleBuild build = new AssetBundleBuild();
                build.assetBundleName = dpAsset.name;
                build.assetNames      = dpAsset.files.ToArray(); //每个依赖列表打成一个包
                bundleBuilds.Add(build);
            }

            int bdlIdx     = 0;
            int combineNum = genInfo.combineNum;

            List <AssetGroup> newAssets  = new List <AssetGroup>();
            List <AssetGroup> assetInfos = genInfo.assets;

            while (bdlIdx < assetInfos.Count)
            {
                AssetGroup assetInfo = assetInfos[bdlIdx];

                AssetBundleBuild build = new AssetBundleBuild();
                var dpAssetSet         = new HashSet <AssetGroup>();

                //按分包数收集包含的所有files
                List <string> files = new List <string>();
                for (int i = 0; i < combineNum && bdlIdx < assetInfos.Count; ++i)
                {
                    files.AddRange(assetInfos[bdlIdx].files);    //添加文件路径

                    List <AssetGroup> dpAssets = assetInfos[bdlIdx].dpAssets;
                    foreach (AssetGroup dpAsset in dpAssets)
                    {
                        dpAssetSet.Add(dpAsset);
                    }
                    ++bdlIdx;
                }


                //重定义名称
                if (combineNum > 1 && !string.IsNullOrEmpty(genInfo.bundleName)) //需要分包
                {
                    var name    = assetInfo.name.Replace("\\", "/");             //只取第一个asset的话,感觉会有问题, 如果里面掺杂了其他remainName,会单独打出一个包了
                    var lastIdx = name.LastIndexOf("/");

                    var remainPath = name.Substring(0, lastIdx);                                     //Resources\GUI\cn\Prefab
                    var remainName = Path.GetFileName(remainPath);                                   //Prefab  其实就是文件夹名称
                    remainPath = remainPath.Substring(0, remainPath.Length - remainName.Length - 1); //Resources\GUI\cn
                    int idxSuffix = 0;
                    if (!genInfo.curCombineIdx.ContainsKey(remainName))                              //这里有点繁琐,可以优化一下
                    {
                        genInfo.curCombineIdx[remainName] = 0;
                    }
                    idxSuffix = genInfo.curCombineIdx[remainName];
                    genInfo.curCombineIdx[remainName] = idxSuffix + 1;

                    assetInfo.name        = BundleUtility.GetBundleOutputName(remainPath + "/" + remainName + "_" + idxSuffix.ToString());
                    build.assetBundleName = assetInfo.name;
                }
                else
                {
                    assetInfo.name        = BundleUtility.GetBundleOutputName(assetInfo.name); //格式化成输出用的名称
                    build.assetBundleName = assetInfo.name;
                }

                assetInfo.files = files;        //覆盖为新的文件列表
                newAssets.Add(assetInfo);       //添加到新的asset列表

                //覆盖为新的依赖列表
                List <AssetGroup> newDpAssets = new List <AssetGroup>();
                foreach (AssetGroup dpAsset in dpAssetSet)
                {
                    newDpAssets.Add(dpAsset);
                }
                assetInfo.dpAssets = newDpAssets;

                build.assetNames = files.ToArray();
                bundleBuilds.Add(build);
            }

            //覆盖为新的Asset列表
            genInfo.assets = newAssets;

            if (needBuild)
            {
                //执行打包
                AssetBundleManifest manifest = BuildPipeline.BuildAssetBundles(PATH_BUNDLE_ROOT, bundleBuilds.ToArray(), CurrentBuildAssetOpts, m_buildTarget);
                //根据manifest矫正一下依赖情况
                BundleUtility.ResetDependsByManifest(manifest, genInfo);
            }

            return(bundleBuilds);
        }
Beispiel #9
0
        static public void Export(List <BundleGenInfo> genInfos_)
        {
            //收集bundle节点
            var bdlNodes = new List <BdlNode>();


            HashSet <string>  assetNameSet = new HashSet <string>();
            List <AssetGroup> assetInfos   = new List <AssetGroup>();


            //收集assetInfo
            foreach (BundleGenInfo genInfo in genInfos_)
            {
                //收集顶级文件
                foreach (AssetGroup assetInfo in genInfo.assets)
                {
                    if (!assetNameSet.Contains(assetInfo.name))
                    {
                        assetNameSet.Add(assetInfo.name);
                        assetInfos.Add(assetInfo);
                    }
                }

                //收集依赖
                foreach (AssetGroup assetInfo in genInfo.assets)
                {
                    foreach (var dpAsset in assetInfo.dpAssets)
                    {
                        if (!assetNameSet.Contains(dpAsset.name))
                        {
                            assetNameSet.Add(dpAsset.name);
                            assetInfos.Add(dpAsset);
                        }
                    }
                }
            }

            //排序
            assetInfos.Sort((a, c) =>
            {
                if (a.isPatch && (!c.isPatch))
                {
                    return(1);
                }
                if ((!a.isPatch) && (c.isPatch))
                {
                    return(-1);
                }

                return(a.name.CompareTo(c.name));
            });

            //分配id
            int id = 0;

            for (int i = 0; i < assetInfos.Count; ++i)
            {
                if (assetInfos[i].bundleId == null)
                {
                    assetInfos[i].bundleId = (id + BUNDLE_IDX_BEGIN).ToString();
                    ++id;
                }
            }

            //再按id排一次序
            assetInfos.Sort((a, c) =>
            {
                return(a.bundleId.CompareTo(c.bundleId));
            });

            BdlNode bdlNode;

            for (var i = 0; i < assetInfos.Count; ++i)
            {
                AssetGroup assetInfo = assetInfos[i];
                bdlNode            = new BdlNode();
                bdlNode.bundleId   = assetInfo.bundleId;
                bdlNode.bundleName = assetInfo.name.ToLower();

                List <string> dependIds = new List <string>();
                foreach (AssetGroup dpAsset in assetInfo.dpAssets)   //收集依赖包的id
                {
                    dependIds.Add(dpAsset.bundleId);
                }

                bdlNode.depends = dependIds.ToArray();

                bdlNodes.Add(bdlNode);
            }

            //收集资源节点
            var     resNodes = new List <ResNode>();
            ResNode resNode;

            foreach (var assetInfo in assetInfos)
            {
                if (assetInfo.isTopFile)
                {
                    //是顶级文件
                    foreach (string path in assetInfo.files)
                    {
                        string resPath = RestoreResPath(path);  //还原为游戏里用到的路径(asset下)

                        if (!string.IsNullOrEmpty(resPath))
                        {
                            resNode          = new ResNode();
                            resNode.path     = resPath;
                            resNode.bundleId = assetInfo.bundleId;
                            resNode.suffix   = Path.GetExtension(path);
                            resNodes.Add(resNode);

                            if (resNode.suffix.ToLower() != ".unity") // 除场景其他小写
                            {
                                resNode.path = resNode.path.ToLower();
                            }
                        }
                    }
                }
            }


            var nodeMap = new BdlNodeMap();

            nodeMap.bdlNodes = bdlNodes.ToArray();
            nodeMap.resNodes = resNodes.ToArray();

            string exportPath = Path.Combine(BundleBuilder.PATH_RES_CFG, CFG_FILE_NAME);

            JsonUtil.WriteToJson(nodeMap, exportPath, true);

            Debug.Log("导出资源配置: " + exportPath);
        }