Esempio n. 1
0
        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);
                }
            }
        }
Esempio n. 2
0
        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);
            }
        }
Esempio n. 3
0
        public static Dictionary <string, long> GetLastBuildAssetsSizes(string buildLogPath, Dictionary <string, long> scenes)
        {
            Log.Debug("Using editor log at: {0}", buildLogPath);

            // copying log
            var tempFileName = ReliablePath.GetTempFileName();
            Dictionary <string, long> assets = new Dictionary <string, long>();

            try
            {
                File.Copy(buildLogPath, tempFileName, true);
                List <string> assetsLines = null;

#if UNITY_2017_1_OR_NEWER
                var parsingLevels  = false;
                var levelSizeRegex = new Regex(@"Level \d+ '(.*)' uses .* ([\d.]+) ([MK]B) uncompressed", RegexOptions.IgnoreCase | UnityVersionAgnostic.CompiledRegexOptions);
#endif

                int lineCount = 0;

                using (ProfileSection.Create("Reading Log"))
                    using (var reader = new StreamReader(File.Open(tempFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
                    {
                        for (string line = reader.ReadLine(); line != null; line = reader.ReadLine(), ++lineCount)
                        {
                            if (line.StartsWith("Used Assets") && line.EndsWith("sorted by uncompressed size:"))
                            {
                                Log.Debug("Found assets marker in the log at line {0}", lineCount);
                                if (assetsLines == null)
                                {
                                    assetsLines = new List <string>();
                                }
                                else
                                {
                                    assetsLines.Clear();
                                }
                            }
                            else if (assetsLines != null)
                            {
                                assetsLines.Add(line);
                            }

#if UNITY_2017_1_OR_NEWER
                            if (line.Equals("***Player size statistics***", StringComparison.OrdinalIgnoreCase))
                            {
                                Log.Debug("Found level statistics start at line {0}", lineCount);
                                scenes.Clear();
                                parsingLevels = true;
                            }
                            else if (parsingLevels)
                            {
                                var match = levelSizeRegex.Match(line);
                                if (match.Success)
                                {
                                    Log.Debug("Found level size at line {0}: {1}", lineCount, match.Value);
                                    var path = match.Groups[1].Value;

                                    var size = SafeParseUnitySize(match.Groups[2].Value, match.Groups[3].Value, path);

                                    long existingSize;
                                    if (!scenes.TryGetValue(path, out existingSize))
                                    {
                                        scenes.Add(path, size);
                                    }
                                    else
                                    {
                                        scenes[path] += size;
                                    }
                                }
                                else
                                {
                                    Log.Debug("Level statistics ended at {0}", lineCount);
                                    parsingLevels = false;
                                }
                            }
#endif
                        }

                        if (assetsLines == null)
                        {
                            throw new ArgumentException("No asset info found in the log");
                        }
                    }

                // now go through all the lines until separator is found
                using (ProfileSection.Create("Parsing Assets"))
                {
                    // line example:  8.1 mb	 1.1% Assets/UI/Menu/HUB/SpriteSheets/HUBSpriteSheetMapRegions.png
                    // unity 5.6.1 has a bug:  2.7 mb	 1.$% Resources/unity_builtin_extra
                    //                   mac:  2.7 mb    inf% Resources/unity_builtin_extra
                    var assetRegex = new Regex(@"^\s*(\d+\.\d+)\s*([mk]b)\s*(?:\d+\.[\d\$]+|inf)%\s*(.*)$", UnityVersionAgnostic.CompiledRegexOptions);

                    // get assets and sizes
                    foreach (var line in assetsLines)
                    {
                        var match = assetRegex.Match(line);
                        if (!match.Success)
                        {
                            break;
                        }

                        var path = match.Groups[3].Value;

                        if (path.StartsWith(SpriteAtlasPrefix))
                        {
                            // ignore this, on Android size seems ok, but on PC & iOS it's complete bollocks
                            // 2017_3_1: for new sprites atlases, this entry "merges" by resolution, which is utterly useless
                            continue;
                        }

                        assets.Add(path, SafeParseUnitySize(match.Groups[1].Value, match.Groups[2].Value, path));
                    }
                }
            }
            finally
            {
                try
                {
                    File.Delete(tempFileName);
                }
                catch (System.Exception) { }
            }

            return(assets);
        }