private static void AddDependenciesInfo(string bundleName, string relativePath, ref DependenciesInfo info,
                                                ref ReservedSharedBundleInfo reserved, ref DependencyCache cache)
        {
            var dependencies = CollectDependencies(relativePath, ref cache);
            var deps         = dependencies.ToList();

            deps.Add(relativePath);

            foreach (var dependency in deps)
            {
                if (!info.ContainsKey(dependency))
                {
                    info[dependency] = new DependencyInfo();
                }

                if (IsShader(dependency))
                {
                    if (BundlerBuildSettings.kSeparateShaderBundle)
                    {
                        info[dependency].referenceInBundles.Add(BundlerBuildSettings.kSeparatedShaderBundleName);
                        reserved[dependency] = BundlerBuildSettings.kSeparatedShaderBundleName;
                    }
                }
                info[dependency].referenceInBundles.Add(bundleName);
            }
        }
        private static DependenciesInfo ParseBundleDependenciesFromRules(BundlerBuildRule buildRule,
                                                                         ref ReservedSharedBundleInfo reserved, ref DependencyCache cache)
        {
            buildRule.rules.Sort((a, b) => - a.shared.CompareTo(b.shared));

            var depsInfo = new DependenciesInfo();

            foreach (var rule in buildRule.rules)
            {
                var packType = (PackType)Enum.Parse(typeof(PackType), rule.packType);
                switch (packType)
                {
                case PackType.PackByFile:
                    ParseBundleDependenciesByRuleOfPackByFile(rule, ref depsInfo, ref reserved, ref cache);
                    break;

                case PackType.PackByDirectory:
                    ParseBundleDependenciesByRuleOfPackByDirectory(rule, ref depsInfo, ref reserved, ref cache);
                    break;

                case PackType.PackBySubDirectory:
                    ParseBundleDependenciesByRuleOfPackBySubDirectory(rule, ref depsInfo, ref reserved, ref cache);
                    break;

                default:
                    throw new ArgumentOutOfRangeException(rule.packType);
                }
            }

            return(depsInfo);
        }
        public static BundlerManifest GenerateManifest(BundlerBuildRule buildRule)
        {
            var cache = LoadAssetDependenciesCache();
            var reservedSharedBundle = new ReservedSharedBundleInfo();
            var depsInfo             = ParseBundleDependenciesFromRules(buildRule, ref reservedSharedBundle, ref cache);
            var bundlesInfo          = GenerateBundlesInfo(ref depsInfo, ref reservedSharedBundle, ref cache);

            ResolveBundleDependencies(ref bundlesInfo, ref cache);
            //FilterRedundantDependencies(ref bundlesInfo);
            var manifest = GenerateBundlerManifest(ref bundlesInfo);

            Resources.UnloadUnusedAssets();
            SaveAssetDependenciesCache(cache);
            return(manifest);
        }
        private static BundlesInfo GenerateBundlesInfo(ref DependenciesInfo depsInfo,
                                                       ref ReservedSharedBundleInfo reserved, ref DependencyCache cache)
        {
            var sharedBundles     = ParseSharedBundleInfo(ref depsInfo, ref reserved, ref cache);
            var noneSharedBundles = ParseNoneSharedBundleInfo(ref depsInfo, ref sharedBundles);

            var bundles = new BundlesInfo();

            sharedBundles.Concat(noneSharedBundles).ToList().ForEach(kv => {
                if (kv.Value.assets.Count > 0)
                {
                    bundles.Add(kv.Key, kv.Value);
                }
            });
            return(bundles);
        }
        private static void ParseBundleDependenciesByRuleOfPackBySubDirectory(BundleRule rule, ref DependenciesInfo depsInfo,
                                                                              ref ReservedSharedBundleInfo reserved, ref DependencyCache cache)
        {
            var excludePattern = rule.excludePattern;

            var searchPath     = PathUtility.RelativeProjectPathToAbsolutePath(rule.path);
            var subDirectories = Directory.GetDirectories(searchPath, "*.*", (SearchOption)rule.depth)
                                 .Where(v => !IsExclude(v, excludePattern))
                                 .ToArray();

            foreach (var subDirectory in subDirectories)
            {
                var files = Directory
                            .GetFiles(subDirectory, rule.searchPattern, SearchOption.AllDirectories)
                            .Where(v => !IsMeta(v))
                            .Where(v => !IsExclude(v, excludePattern))
                            .ToArray();

                var bundleName = PathUtility.NormalizeAssetBundlePath(subDirectory);
                bundleName = string.Format(BundlerBuildSettings.kBundleFormatter, bundleName);
                bundleName = BundlerBuildSettings.kHashAssetBundlePath
                    ? PathUtility.HashPath(bundleName)
                    : bundleName;

                try {
                    var index = 0;
                    foreach (var file in files)
                    {
                        EditorUtility.DisplayProgressBar("Parsing Rule of Pack By Sub Directory Name", file,
                                                         (float)index++ / files.Length);

                        var relativePath = PathUtility.AbsolutePathToRelativeProjectPath(file);
                        if (rule.shared)
                        {
                            TryAddToForceSharedBundle(relativePath, bundleName, ref reserved);
                        }

                        AddDependenciesInfo(bundleName, relativePath, ref depsInfo, ref reserved, ref cache);
                    }
                }
                finally {
                    EditorUtility.ClearProgressBar();
                }
            }
        }
        private static BundlesInfo ParseSharedBundleInfo(ref DependenciesInfo depsInfo,
                                                         ref ReservedSharedBundleInfo reserved, ref DependencyCache cache)
        {
            var sharedDict = new Dictionary <string, string>();

            var index = 0;

            // Determine shared bundles
            foreach (var kv in depsInfo)
            {
                var asset = kv.Key;

                // Ignore this asset when forced build in shared bundle.
                if (reserved.ContainsKey(asset))
                {
                    continue;
                }

                var depSet = kv.Value;

                // The count of dependencies no greater than 1 means that there are no other bundles
                // sharing this asset
                if (depSet.referenceInBundles.Count <= 1)
                {
                    continue;
                }

                // Otherwise, assets which depended by the same bundles will be separated to shared bundle.
                if (!sharedDict.ContainsKey(asset))
                {
                    sharedDict[asset] = string.Format(BundlerBuildSettings.kSharedBundleFormatter,
                                                      (++index).ToString());

                    // Sub-assets dependencies.
                    var deps = CollectDependencies(asset, ref cache);
                    foreach (var dep in deps)
                    {
                        if (reserved.ContainsKey(dep))
                        {
                            continue;
                        }
                        sharedDict[dep] = string.Format(BundlerBuildSettings.kSharedBundleFormatter,
                                                        (++index).ToString());
                    }
                }
            }

            // Collect shared bundles info
            var bundlesInfo = new BundlesInfo();

            foreach (var kv in sharedDict)
            {
                var name = sharedDict[kv.Key];
                if (bundlesInfo.ContainsKey(name))
                {
                    throw new BundleException("Shared bundle duplicated: " + name);
                }

                bundlesInfo[name] = new BundleInfo();
                bundlesInfo[name].assets.Add(kv.Key);
            }

            // Generate unique bundle name according to assets list.
            var sharedBundle = new BundlesInfo();

            foreach (var kv in bundlesInfo)
            {
                var assets = kv.Value.assets.ToList();
                assets.Sort((a, b) => string.Compare(a, b, StringComparison.Ordinal));

                var bundleName = string.Join("-", assets.ToArray());
                if (BundlerBuildSettings.kHashSharedBundle)
                {
                    using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(bundleName)))
                    {
                        var nameHash = CalculateMd5(stream);
                        bundleName = string.Format(BundlerBuildSettings.kSharedBundleFormatter, nameHash);
                    }
                }
                else
                {
                    bundleName = string.Format(BundlerBuildSettings.kSharedBundleFormatter, bundleName.ToLower());
                }

                var bundleInfo = new BundleInfo();
                foreach (var asset in kv.Value.assets)
                {
                    bundleInfo.assets.Add(asset);
                }
                sharedBundle.Add(bundleName, bundleInfo);
            }

            // Add reserved shared bundles info
            foreach (var kv in reserved)
            {
                var assetName = kv.Key;
                var bundle    = kv.Value;
                if (!sharedBundle.ContainsKey(bundle))
                {
                    sharedBundle.Add(bundle, new BundleInfo());
                }
                sharedBundle[bundle].assets.Add(assetName);
            }

            return(sharedBundle);
        }
 private static void TryAddToForceSharedBundle(string assetName, string bundleName, ref ReservedSharedBundleInfo reserved)
 {
     if (reserved.ContainsKey(assetName))
     {
         throw new BundleRuleConflictException(
                   string.Format("Asset({0} has already contain in bundle: {1}, but trying add to new bundle: {2})",
                                 assetName, reserved[assetName], bundleName));
     }
     reserved.Add(assetName, bundleName);
 }