private static IEnumerable <string> CollectDependencies(string asset, ref DependencyCache cache) { // Try get dependencies from cache var assetGuid = AssetDatabase.AssetPathToGUID(asset); if (cache.cacheData.TryGetValue(assetGuid, out var cacheData)) { if (ValidateDependency(ref cache, cacheData)) { return(cacheData.dependencies.Select(AssetDatabase.GUIDToAssetPath).ToList()); } } return(AnalyzeDependencies(asset, ref cache)); }
private static void ResolveBundleDependencies(ref BundlesInfo bundlesInfo, ref DependencyCache cache) { var info = bundlesInfo; var cacheData = cache; foreach (var kv in bundlesInfo) { //Debug.Log(string.Format("Resolving bundle dependency: {0}", kv.Key)); var bundleInfo = kv.Value; bundleInfo.dependencies.Clear(); void ResolveAssetDependency(string asset) { var dependencies = CollectDependencies(asset, ref cacheData); foreach (var dependencyAsset in dependencies) { // Which bundle contains this asset? var depBundle = info.FirstOrDefault( v => v.Value.assets.Contains(dependencyAsset)).Key; if (string.IsNullOrEmpty(depBundle)) { continue; } if (depBundle == kv.Key) { continue; } if (bundleInfo.dependencies.Contains(depBundle)) { continue; } bundleInfo.dependencies.Add(depBundle); } } foreach (var asset in bundleInfo.assets) { ResolveAssetDependency(asset); } } }
private NewDependencyCache() { m_cache = new DependencyCache.Builder { CacheDir = FileHelper.NewTmpDir("deps-cache") }.Build(); }
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 bool ValidateDependency(ref DependencyCache cache, DependencyCacheData cacheData) { if (cacheData.validated) { return(true); } var hash = AssetDatabase.GetAssetDependencyHash(cacheData.assetPath); if (cacheData.assetHash != hash) { Debug.LogFormat("Hash not match: {0}, previous: {1}, current: {2}", cacheData.assetPath, cacheData.assetHash, hash); return(false); } var ret = true; foreach (var dependency in cacheData.dependencies) { var dependencyPath = AssetDatabase.GUIDToAssetPath(dependency); if (!File.Exists(PathUtility.RelativeProjectPathToAbsolutePath(dependencyPath))) { Debug.LogFormat("Dependency file missing: {0}, {1}, hash validation not passed: {2}", dependency, dependencyPath, cacheData.assetPath); return(false); } if (cache.cacheData.TryGetValue(dependency, out var data)) { ret &= ValidateDependency(ref cache, data); } else { Debug.LogFormat("Dependency cache data missing: {0}, {1}, hash validation not passed: {2}", dependency, dependencyPath, cacheData.assetPath); return(false); } } foreach (var scriptRef in cacheData.scriptsRefs) { var scriptPath = AssetDatabase.GUIDToAssetPath(scriptRef); if (!File.Exists(PathUtility.RelativeProjectPathToAbsolutePath(scriptPath))) { Debug.LogFormat("Script file missing: {0}, {1}, hash validation not passed: {2}", scriptRef, scriptPath, cacheData.assetPath); return(false); } if (cache.cacheData.TryGetValue(scriptRef, out var data)) { ret &= ValidateDependency(ref cache, data); } else { Debug.LogFormat("Script cache data missing: {0}, {1}, hash validation not passed: {2}", scriptRef, scriptPath, cacheData.assetPath); return(false); } } cacheData.validated = ret; return(ret); }
private static IEnumerable <string> AnalyzeDependencies(string asset, ref DependencyCache cache) { if (++CollectedCount % 2000 == 0) { Debug.Log($"[{CollectedCount}]Unloading assets to reduce memory..."); Resources.UnloadUnusedAssets(); GC.Collect(); } string[] dep1; // On Unity 2018 or newer, LightingDataAsset depends on SceneAsset directly, // which will lead to circular dependency var assetObj = AssetDatabase.LoadAssetAtPath <UnityEngine.Object>(asset); if (assetObj is LightingDataAsset lightingDataAsset) { dep1 = GetLightingDataValidDependencies(lightingDataAsset); } else { dep1 = AssetDatabase.GetDependencies(asset, true); dep1 = dep1.Where(v => !IsBuiltinResource(v)) .Where(v => IsProjectResource(v)) .ToArray(); } var dep2 = dep1.Where(v => v != asset).ToArray(); var dep3 = dep2.Distinct().ToList(); var scriptRefs = dep3.Where(v => IsAssembly(v) || IsScript(v)).ToList(); var assetDeps = dep3.Where(v => !(IsAssembly(v) || IsScript(v))).ToList(); var assetGuid = AssetDatabase.AssetPathToGUID(asset); cache.cacheData[assetGuid] = new DependencyCacheData { assetHash = AssetDatabase.GetAssetDependencyHash(asset), dependencies = assetDeps.Select(AssetDatabase.AssetPathToGUID).ToList(), scriptsRefs = scriptRefs.Select(AssetDatabase.AssetPathToGUID).ToList(), validated = true, }; foreach (var dep in assetDeps) { var guid = AssetDatabase.AssetPathToGUID(dep); if (!cache.cacheData.ContainsKey(guid) || !ValidateDependency(ref cache, cache.cacheData[guid])) { AnalyzeDependencies(dep, ref cache); } } foreach (var dep in scriptRefs) { var guid = AssetDatabase.AssetPathToGUID(dep); if (!cache.cacheData.ContainsKey(guid) || !ValidateDependency(ref cache, cache.cacheData[guid])) { AnalyzeDependencies(dep, ref cache); } } assetDeps.Sort(); return(assetDeps); }
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 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 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 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); }
private static void SaveAssetDependenciesCache(DependencyCache cache) { var jsonData = JsonUtility.ToJson(cache); File.WriteAllText(DependenciesCacheFilePath, jsonData); }
private string[] GetDependencyEntries(string currentDependencyDirectoryPath) { string currentDependencyFilePath = VirtualPath.Combine('/', currentDependencyDirectoryPath, ".dep"); DependencyCache dependencyCacheEntry = null; if (!dependencyCache.TryGetValue(currentDependencyFilePath, out dependencyCacheEntry) || dependencyCacheEntry.dependencyListLastModified < File.GetLastWriteTime(currentDependencyFilePath)) { dependencyCacheEntry = new DependencyCache() { dependencyListLastModified = File.GetLastWriteTime(currentDependencyFilePath), dependencyList = File.ReadAllLines(this.Context.Server.MapPath(currentDependencyFilePath)) }; VirtualFileAssembler.dependencyCache[currentDependencyFilePath] = dependencyCacheEntry; } return dependencyCacheEntry.dependencyList; }