public static void CalculateScriptReferences(List<AssetInfo> infos, BuildInfoAssetDetailsCollector collector) { // count asset references var scripts = collector.AcquireValidScripts().ToDictionary(x => x, x => 0); foreach (var info in infos) { foreach (var dep in info.dependencies) { int count; if (scripts.TryGetValue(dep, out count)) { scripts[dep] = ++count; } } } foreach (var script in scripts) { var scriptInfoIndex = FindInfoIndexByPath(infos, script.Key); if (scriptInfoIndex < 0) throw new InvalidOperationException("Unable to find script's index: " + script.Key); var scriptInfo = infos[scriptInfoIndex]; SetCustomProperty(scriptInfo, "ScriptReferences", scriptInfo.scenes.Count + script.Value); } }
public static void FinishCalculatingCompressedSizes(List<AssetInfo> infos, BuildInfoAssetDetailsCollector collector) { var compressedSizes = collector.AcquireCalculatedCompressedSizes(15000); foreach (var kv in compressedSizes) { var index = FindInfoIndexByPath(infos, kv.Key); if (index >= 0) { long prevSize = UpdateCompressedSize(infos[index], kv.Value, addSize: false); if (prevSize != 0 && prevSize != kv.Value) { Log.Debug("Calculated and actual compressed size are different: {0} vs {1}, using the former", prevSize, kv.Value); UpdateCompressedSize(infos[index], prevSize, addSize: false); } } else { Log.Warning("Calculated compressed size for {0}, but not found in resulting assets.", kv.Key); } } }
public static void FinishCollectingDetails(List<AssetInfo> assetsInfo, BuildInfoAssetDetailsCollector collector) { using (ProfileSection.Create("Collecting Assets' Details")) { var details = new List<AssetProperty>(); foreach (var assetInfo in assetsInfo) { if (assetInfo.details != null) { continue; } Log.Debug("Load main asset at: {0}", assetInfo.path); var mainAsset = AssetDatabase.LoadMainAssetAtPath(assetInfo.path); if (mainAsset != null) { details.Clear(); Log.Debug("Collecting details for asset: {0}", assetInfo.path); if (collector.CollectForAsset(details, mainAsset, assetInfo.path)) { assetInfo.details = details.ToArray(); } } } } using (ProfileSection.Create("Cleaning Up Assets' Details")) { // sanitize and sort stuff foreach (var assetInfo in assetsInfo) { assetInfo.details = BuildInfoProcessorUtils.CleanUpAssetsDetails(assetInfo.details, assetInfo.path); } } }
private static IEnumerable<AssetInfo> GetAtlasAssetPages(AssetInfo atlasInfo, BuildInfoAssetDetailsCollector collector) { // add dependencies to atlas textures manually var atlas = AssetDatabase.LoadMainAssetAtPath(atlasInfo.path); if (atlas) { var tag = UnityVersionAgnostic.GetSpriteAtlasTag(atlas); var previewTextures = UnityVersionAgnostic.LoadSpriteAtlasTextues(atlas); if (previewTextures != null && tag != null) { int pageNo = 0; foreach (var texture in previewTextures) { var textureInfo = new AssetInfo() { path = "Sprite Atlas " + tag + " [" + (pageNo + 1) + " of " + previewTextures.Length + "]", spritePackerPage = pageNo, spritePackerTag = tag, size = GetStorageMemorySize(texture), scenes = atlasInfo.scenes.ToList(), }; if (collector != null) { Log.Debug("Collecting details for asset: {0}", textureInfo.path); List<AssetProperty> details = new List<AssetProperty>(); collector.CollectForAsset(details, texture, textureInfo.path); textureInfo.details = details.ToArray(); } yield return textureInfo; ++pageNo; } } else { Log.Warning("No textures found for atlas {0}", atlas); } } }
public static void RefreshScenesInfo(Dictionary<string, long> scenesSizes, List<AssetInfo> infos, BuildArtifactsInfo artifactsInfo, List<string> processedScenes, List<AssetProperty[]> scenesDetails, BuildInfoAssetDetailsCollector collector) { Dictionary<string, AssetInfo> scenesInfo = new Dictionary<string, AssetInfo>(); // if there are missing scenes... add them foreach (var scenePath in processedScenes.Distinct()) { var info = new AssetInfo() { path = scenePath, scenes = { scenePath } }; long size; scenesSizes.TryGetValue(scenePath, out size); info.size = size; scenesInfo.Add(scenePath, info); } if (collector != null) { foreach (var sceneInfo in scenesInfo.Values) { var index = processedScenes.FindIndex(x => string.Compare(x, sceneInfo.path, true) == 0); if (index >= 0) sceneInfo.details = CleanUpAssetsDetails(scenesDetails[index], sceneInfo.path); else Log.Warning("Unable to find details for level {0}", sceneInfo.path); } } infos.AddRange(scenesInfo.Values); if (artifactsInfo != null) { for (int i = 0; i < artifactsInfo.sceneSizes.Count; ++i) { if (i >= processedScenes.Count) { #if !UNITY_2017_1_OR_NEWER Log.Warning("Detected more scenes in the build than been notified of ({0} vs {1})", artifactsInfo.sceneSizes.Count, processedScenes.Count); #endif break; } if (artifactsInfo.sceneSizes[i].uncompressed == 0) { Log.Warning("No size for {0}", processedScenes[i]); } AssetInfo sceneInfo = scenesInfo[processedScenes[i]]; sceneInfo.size = System.Math.Max(artifactsInfo.sceneSizes[i].uncompressed, sceneInfo.size); UpdateCompressedSize(sceneInfo, artifactsInfo.sceneSizes[i].compressed); } } }
public static void DiscoverDependenciesAndMissingAtlases(List<AssetInfo> assetsInfo, Dictionary<string, AssetInfo> assetsUsedByScenes, BuildInfoAssetDetailsCollector collector) { using (ProfileSection.Create("Resolving dependencies")) { Dictionary<string, AssetInfo> discoveredAtlases = new Dictionary<string, AssetInfo>(); Action<UnitySprite, string> legacySpriteAtlasHandler = null; if (UnityVersionAgnostic.IsUsingLegacySpriteAtlases) { legacySpriteAtlasHandler = CreateLegacyAtlasHandler((atlasPageName, atlasPage) => { AssetInfo entry; if (assetsUsedByScenes.TryGetValue(atlasPageName, out entry)) return entry; else if (discoveredAtlases.TryGetValue(atlasPageName, out entry)) return entry; entry = new AssetInfo() { path = atlasPageName }; discoveredAtlases.Add(atlasPageName, entry); if (collector != null) { List<AssetProperty> details = new List<AssetProperty>(); Log.Debug("Collecting details for asset: {0}", atlasPageName); collector.CollectForAsset(details, atlasPage, atlasPageName); entry.details = details.ToArray(); } return entry; }); } // now resolve dependencies and references foreach (var assetInfo in assetsInfo) { Log.Debug("Collecting dependencies for asset: {0}", assetInfo.path); var dependencies = AssetDatabase.GetDependencies(new[] { assetInfo.path }); bool isPossiblyLeakingLegacyAtlasses = legacySpriteAtlasHandler != null && assetInfo.scenes.Count == 0 && (assetInfo.path.IndexOf("/Resources/", StringComparison.OrdinalIgnoreCase) >= 0) && (assetInfo.path.EndsWith(".prefab", StringComparison.OrdinalIgnoreCase) || assetInfo.path.EndsWith(".asset", StringComparison.OrdinalIgnoreCase)); // new sprites need to load their data manually if (UnityVersionAgnostic.IsUsingSpriteAtlases && assetInfo.path.EndsWith(".spriteatlas")) { foreach (var pageInfo in GetAtlasAssetPages(assetInfo, collector)) { if (discoveredAtlases.ContainsKey(pageInfo.path)) { Log.Warning("Atlas already discovered: {0}", pageInfo.path); } else { discoveredAtlases.Add(pageInfo.path, pageInfo); assetInfo.dependencies.Add(pageInfo.path); } } assetInfo.dependencies.Sort(); } bool mayHaveAnySpritesFromAtlases = false; foreach (var dependency in dependencies) { if (dependency == assetInfo.path) continue; int dependencyIndex = assetInfo.dependencies.BinarySearch(dependency); if (dependencyIndex < 0) { assetInfo.dependencies.Insert(~dependencyIndex, dependency); } if (!isPossiblyLeakingLegacyAtlasses) continue; var textureImporter = AssetImporter.GetAtPath(dependency) as TextureImporter; if (textureImporter != null && textureImporter.qualifiesForSpritePacking) { // oh noes mayHaveAnySpritesFromAtlases = true; } } if (mayHaveAnySpritesFromAtlases) { Log.Debug("Asset {0} may be leaking some texture atlases, going to do a slow check", assetInfo.path); // sad panda var asset = AssetDatabase.LoadMainAssetAtPath(assetInfo.path); if (!asset) { Log.Warning("Unable to do a slow texture atlas check for {0}", assetInfo.path); } else { var assetDependencies = EditorUtility.CollectDependencies(new[] { asset }) .OfType<UnitySprite>(); foreach (var sprite in assetDependencies) { var spriteAssetPath = AssetDatabase.GetAssetPath(sprite); if (!string.IsNullOrEmpty(spriteAssetPath)) { legacySpriteAtlasHandler(sprite, spriteAssetPath); } } } } } assetsInfo.AddRange(discoveredAtlases.Values); } }