public Dictionary <string, Dictionary <string, List <string> > > BuildBundleContent(Queue <string> fileUrls)
        {
            Dictionary <string, Dictionary <string, List <string> > > result = new Dictionary <string, Dictionary <string, List <string> > >();

            foreach (string fileUrl in fileUrls)
            {
                Console.WriteLine("loading bundle data from url: " + fileUrl);
                using var client = new WebClient();
                using var stream = new MemoryStream(client.DownloadData(fileUrl));
                var assetToolUtils = new AssetToolUtils();
                Console.WriteLine("Download done, building AssetsFileInstance...");
                foreach (AssetFile file in assetToolUtils.BuildAssetsFileInstance(stream))
                {
                    try {
                        BuildBundleContent(ref result, fileUrl, file, assetToolUtils);
                    } catch (Exception e) {
                        Console.WriteLine("failed to parse bundle! blame AssetTools...");
                        Console.WriteLine("Exception: " + e.Message);
                        Console.WriteLine(e.StackTrace);
                    }
                }

                assetToolUtils.CloseActiveStreams();
            }

            return(result);
        }
        private void Run()
        {
            EOnlineDataType onlineDataType = materialExtractor.onlineSourcesConfig.GetValue().dataType.GetValue();

            switch (onlineDataType)
            {
            case EOnlineDataType.bundleFile:
                Dictionary <string, List <string> > materialToColorList = new Dictionary <string, List <string> >();
                foreach (string dataFileUrL in materialExtractor.onlineSourcesConfig.GetValue().GetDataFileURLs())
                {
                    if (!materialExtractor.downloadSettings.GetValue().doDownload.GetValue())
                    {
                        Console.WriteLine("would download: " + dataFileUrL);
                        continue;
                    }

                    List <string> pathConstraints = new List <string> {
                        "m_SavedProperties:m_Colors:Array:data:first=_PrimaryColor",
                        "m_SavedProperties:m_Colors:Array:data:first=_SecondaryColor",
                        "m_SavedProperties:m_Colors:Array:data:first=_TertiaryColor"
                    };

                    try {
                        Console.WriteLine("loading bundle data from url: " + dataFileUrL);
                        using var client = new WebClient();
                        using var stream = new MemoryStream(client.DownloadData(dataFileUrL));
                        var assetToolUtils = new AssetToolUtils();
                        Console.WriteLine("Download done, building AssetsFileInstance...");
                        foreach (AssetFile file in assetToolUtils.BuildAssetsFileInstance(stream))
                        {
                            foreach (AssetFileInfoEx info in file.fileInstance.table.assetFileInfo)
                            {
                                ClassDatabaseType type = AssetHelper.FindAssetClassByID(file.classDBFile, info.curFileType);
                                if (type == null)
                                {
                                    continue;
                                }

                                string typeName = type.name.GetString(file.classDBFile);
                                if (typeName != "Material")
                                {
                                    continue;
                                }

                                AssetTypeValueField baseField = AssetToolUtils.GetATI(file, info).GetBaseField();
                                string materialName           = AssetToolUtils.GetFieldAtPath(file, baseField, "m_Name".Split(":")).FirstOrDefault()?.GetValue()?.AsString();
                                if (materialName == null)
                                {
                                    continue;
                                }

                                Console.WriteLine($"\tchecking Material '{materialName}'");

                                if (!AssetToolUtils.IsMatchingPathConstraints(file, baseField, pathConstraints))
                                {
                                    Console.WriteLine("\t\tMaterial did not match path constraints!");
                                    continue;
                                }

                                List <string> colors = new List <string> {
                                    "", "", ""
                                };
                                foreach (AssetTypeValueField colorDataField in AssetToolUtils.GetFieldAtPath(file, baseField, "m_SavedProperties:m_Colors:Array:data".Split(":")))
                                {
                                    string red   = AssetToolUtils.GetFieldAtPath(file, colorDataField, "second:r".Split(":")).FirstOrDefault()?.GetValue()?.AsString();
                                    string green = AssetToolUtils.GetFieldAtPath(file, colorDataField, "second:g".Split(":")).FirstOrDefault()?.GetValue()?.AsString();
                                    string blue  = AssetToolUtils.GetFieldAtPath(file, colorDataField, "second:b".Split(":")).FirstOrDefault()?.GetValue()?.AsString();
                                    string alpha = AssetToolUtils.GetFieldAtPath(file, colorDataField, "second:a".Split(":")).FirstOrDefault()?.GetValue()?.AsString();
                                    if (red == null || green == null || blue == null || alpha == null)
                                    {
                                        Console.WriteLine("\t\trgba was null!");
                                        continue;
                                    }
                                    string colorString = $"r={red};g={green};b={blue};a={alpha}";

                                    if (AssetToolUtils.IsMatchingPathConstraints(file, colorDataField, "first=_PrimaryColor"))
                                    {
                                        colors[0] = colorString;
                                    }
                                    else if (AssetToolUtils.IsMatchingPathConstraints(file, colorDataField, "first=_SecondaryColor"))
                                    {
                                        colors[1] = colorString;
                                    }
                                    else if (AssetToolUtils.IsMatchingPathConstraints(file, colorDataField, "first=_TertiaryColor"))
                                    {
                                        colors[2] = colorString;
                                    }
                                }
                                materialToColorList[materialName] = colors;
                            }
                        }
                    } catch (Exception e) {
                        Console.WriteLine($"\tEncountered an exception! {e}");
                        if (materialExtractor.downloadSettings.GetValue().pauseDownloadOnError.GetValue())
                        {
                            Console.WriteLine("\twaiting for user acknowledgement. Press any key to continue...");
                            Console.ReadKey(true);
                        }
                    }
                }

                string targetFile      = materialExtractor.GetResultFile("extraction");
                string targetDirectory = Path.GetDirectoryName(targetFile);
                if (!Directory.Exists(targetDirectory))
                {
                    Console.WriteLine("Had to create directory: " + targetDirectory);
                    Directory.CreateDirectory(targetDirectory);
                }

                using (StreamWriter writer = new StreamWriter(targetFile, false)) {
                    List <string> header = new List <string> {
                        "MaterialName", "Primary", "Secondary", "Tertiary"
                    };
                    Console.WriteLine(string.Join("\t", header));
                    writer.WriteLine(string.Join("\t", header));
                    foreach ((string materialName, List <string> colorsInOrder) in materialToColorList)
                    {
                        Console.WriteLine(materialName + "\t" + string.Join("\t", colorsInOrder));
                        writer.WriteLine(materialName + "\t" + string.Join("\t", colorsInOrder));
                    }
                }

                break;

            case EOnlineDataType.xmlFile:
            default:
                throw new InvalidOperationException("OnlineDataType " + onlineDataType + " not supported by MaterialExtractor!");
            }

            Console.WriteLine("Press any key to continue.");
            Console.ReadKey(true);
        }