private void onLoadProgress(LoadProgressMessage message)
        {
            if (message.IsComplete)
            {
                viewModel.JobProgressVisibility = false;
                viewModel.JobProgress           = 0.0;
                viewModel.JobProgressText       = "Idle";

                lastCurrent = 0;

                return;
            }

            viewModel.JobProgressVisibility = message.Total > 0;
            viewModel.JobProgressText       = message.Total > 0 ? $"{message.Text} [{message.Current:N0} / {message.Total:N0}]" : message.Text;

            if (message.Current == 0)
            {
                lastCurrent = 0;
            }

            if (message.Current > 0 && message.Total > 0 && message.Current > lastCurrent)
            {
                viewModel.JobProgress = message.Current / message.Total * 100.0;

                lastCurrent = message.Current;
            }

            if (message.StatusText != null)
            {
                viewModel.StatusText = message.StatusText;
            }
        }
        private void onLoadProgress(LoadProgressMessage message)
        {
            if (!message.IsComplete)
            {
                return;
            }

            isLocalMode = message.IsLocalMode;
        }
Beispiel #3
0
        private async Task onLoadProgressAsync(LoadProgressMessage message)
        {
            //
            // This method alwyas runs on a background thread.  Executed at program start only.
            //
            // Due to requirements of the Bitmap class (used by FontAwesome) the entities must be created on the
            // UI thread.
            //
            await asyncService.RunUiContext(() => viewModel.Loaders = buildEntityList());

            messenger.SendUi(new OpenDialogMessage {
                Name = DialogNames.LoadProgressDialog
            });

            await commonDataStore.LoadDataFilesAsync(onProgressCallbackAsync, false);
        }
        private void buildObjectParents(CancellationToken token)
        {
            LoadProgressMessage message = new LoadProgressMessage {
                Text = "Building Object Tree..."
            };

            messenger.SendUi(message);

            try
            {
                List <ObjectTreeViewEntity> packages = imports.Where(import => import.OwnerReferenceNameIndex == null)
                                                       .Select(import => import.PackageNameIndex.Name)
                                                       .Distinct()
                                                       .Select(packageName => new ObjectTreeViewEntity {
                    Name = packageName, IsExpanded = packageName.Equals("Core", StringComparison.CurrentCultureIgnoreCase)
                })
                                                       .ToList();

                viewModel.ObjectTree = new ObservableCollection <ObjectTreeViewEntity>(packages.OrderBy(package => package.Name));

                foreach (ObjectTreeViewEntity package in packages)
                {
                    List <ObjectTreeViewEntity> firstTypes = imports.Where(import => import.OwnerReferenceNameIndex == null &&
                                                                           package.Name == import.PackageNameIndex.Name)
                                                             .Select(import => import.TypeNameIndex.Name)
                                                             .Distinct()
                                                             .Select(typeName1 => new ObjectTreeViewEntity {
                        Name = typeName1, Parent = package, IsExpanded = typeName1.Equals("Package", StringComparison.CurrentCultureIgnoreCase)
                    })
                                                             .ToList();

                    package.Children = new ObservableCollection <ObjectTreeViewEntity>(firstTypes.OrderBy(type => type.Name));

                    List <string> names = new List <string> {
                        "Engine", "Core"
                    };

                    foreach (ObjectTreeViewEntity type1 in firstTypes)
                    {
                        List <ObjectTreeViewEntity> firstNames = imports.Where(import => import.OwnerReferenceNameIndex == null &&
                                                                               package.Name == import.PackageNameIndex.Name &&
                                                                               type1.Name == import.TypeNameIndex.Name)
                                                                 .Select(import => import.NameTableIndex.Name)
                                                                 .Distinct()
                                                                 .Select(name1 => new ObjectTreeViewEntity {
                            Name = name1, Parent = type1, IsExpanded = names.Contains(name1)
                        })
                                                                 .ToList();

                        type1.Children = new ObservableCollection <ObjectTreeViewEntity>(firstNames.OrderBy(name => name.Name));

                        recursiveImports(firstNames);
                    }
                }
            }
            catch (Exception ex)
            {
                messenger.SendUi(new ApplicationErrorMessage {
                    HeaderText = "Error Building Object Tree", Exception = ex
                });
            }

            message.IsComplete = true;

            messenger.SendUi(message);
        }
Beispiel #5
0
        private async Task rebuildExports()
        {
            Dictionary <ExportedObjectViewEntity, List <ExportedObjectViewEntity> > filesToMod = viewModel.ExportsTree?.Traverse(e => Path.HasExtension(e.Filename) && e.IsChecked)
                                                                                                 .GroupBy(e => e.Parent)
                                                                                                 .ToDictionary(g => g.Key, g => g.ToList());

            if (filesToMod == null || !filesToMod.Any())
            {
                return;
            }

            LoadProgressMessage message = new LoadProgressMessage {
                Text = "Rebuilding...", Total = filesToMod.Count
            };

            foreach (KeyValuePair <ExportedObjectViewEntity, List <ExportedObjectViewEntity> > pair in filesToMod)
            {
                string gameFilename = $"{pair.Key.Filename.Replace(settings.ExportPath, null)}.upk";

                DomainUpkFile file = allFiles.SingleOrDefault(f => f.GameFilename.Equals(gameFilename));

                if (file == null)
                {
                    continue;
                }

                DomainHeader header = await repository.LoadUpkFile(Path.Combine(settings.PathToGame, file.GameFilename));

                await header.ReadHeaderAsync(null);

                message.Current++;

                foreach (ExportedObjectViewEntity entity in pair.Value)
                {
                    DomainExportTableEntry export = header.ExportTable.SingleOrDefault(ex => ex.NameTableIndex.Name.Equals(Path.GetFileNameWithoutExtension(entity.Filename), StringComparison.CurrentCultureIgnoreCase));

                    if (export == null)
                    {
                        continue;
                    }

                    await export.ParseDomainObject(header, false, false);

                    int compressor = menuViewModel.IsCompressorClusterFit ? 0 : menuViewModel.IsCompressorRangeFit ? 1 : 2;

                    int errorMetric = menuViewModel.IsErrorMetricPerceptual ? 0 : 1;

                    FileFormat fileFormat = menuViewModel.IsDdsDefault ? FileFormat.Unknown :
                                            menuViewModel.IsDdsFormat1 ? FileFormat.DXT1    :
                                            menuViewModel.IsDdsFormat5 ? FileFormat.DXT5    : FileFormat.A8R8G8B8;

                    DdsSaveConfig config = new DdsSaveConfig(fileFormat, compressor, errorMetric, menuViewModel.IsWeightColorByAlpha, false);

                    await export.DomainObject.SetObject(entity.Filename, header.NameTable, config);

                    message.StatusText = entity.Filename;

                    messenger.Send(message);
                }

                string directory = Path.Combine(settings.PathToGame, Path.GetDirectoryName(file.GameFilename), "mod");

                string filename = Path.Combine(directory, Path.GetFileName(file.GameFilename));

                if (!Directory.Exists(directory))
                {
                    Directory.CreateDirectory(directory);
                }

                await repository.SaveUpkFile(header, filename);

                DomainUpkFile upkFile = new DomainUpkFile {
                    GameFilename = filename.Replace(settings.PathToGame, null), FileSize = new FileInfo(filename).Length, Package = GetFileNameWithoutExtension(filename).ToLowerInvariant()
                };

                messenger.Send(new ModFileBuiltMessage {
                    UpkFile = upkFile
                });
            }

            message.IsComplete = true;
            message.StatusText = null;

            messenger.Send(message);
        }
        private async Task exportFileObjects(List <DomainUpkFile> files)
        {
            LoadProgressMessage message = new LoadProgressMessage {
                Text = "Exporting...", Total = files.Count
            };

            int compressor = menuViewModel.IsCompressorClusterFit ? 0 : menuViewModel.IsCompressorRangeFit ? 1 : 2;

            int errorMetric = menuViewModel.IsErrorMetricPerceptual ? 0 : 1;

            DdsSaveConfig config = new DdsSaveConfig(FileFormat.Unknown, compressor, errorMetric, menuViewModel.IsWeightColorByAlpha, false);

            foreach (DomainUpkFile file in files)
            {
                FileViewEntity fileEntity = viewModel.Files.Single(fe => fe.Id == file.Id);

                string directory = Path.Combine(settings.ExportPath, Path.GetDirectoryName(file.GameFilename), Path.GetFileNameWithoutExtension(file.GameFilename));

                if (!Directory.Exists(directory))
                {
                    Directory.CreateDirectory(directory);
                }

                DomainHeader header = file.Header;

                if (header == null)
                {
                    try {
                        header = await repository.LoadUpkFile(Path.Combine(settings.PathToGame, file.GameFilename));

                        await Task.Run(() => header.ReadHeaderAsync(null));
                    }
                    catch (Exception ex) {
                        messenger.Send(new ApplicationErrorMessage {
                            HeaderText = "Error Loading UPK File", ErrorMessage = $"Filename: {file.GameFilename}", Exception = ex
                        });

                        fileEntity.IsErrored = true;

                        continue;
                    }
                }

                message.Current++;

                foreach (DomainExportTableEntry export in header.ExportTable)
                {
                    if (export.DomainObject == null)
                    {
                        try {
                            await export.ParseDomainObject(header, false, false);
                        }
                        catch (Exception ex) {
                            messenger.Send(new ApplicationErrorMessage {
                                HeaderText = "Error Parsing Object", ErrorMessage = $"Filename: {header.Filename}\nExport Name: {export.NameTableIndex.Name}\nType: {export.TypeReferenceNameIndex.Name}", Exception = ex
                            });

                            fileEntity.IsErrored = true;

                            continue;
                        }
                    }

                    if (!export.DomainObject.IsExportable)
                    {
                        continue;
                    }

                    string filename = Path.Combine(directory, $"{export.NameTableIndex.Name}{export.DomainObject.FileExtension}");

                    message.StatusText = filename;

                    messenger.Send(message);

                    await export.DomainObject.SaveObject(filename, config);
                }

                file.Header = null;
            }

            message.IsComplete = true;
            message.StatusText = null;

            messenger.Send(message);
        }
        private async Task scanUpkFiles(List <DomainUpkFile> upkFiles)
        {
            isScanInProgress = true;

            LoadProgressMessage message = new LoadProgressMessage {
                Text = "Scanning UPK Files", Current = 0, Total = upkFiles.Count
            };

            List <DomainUpkFile> saveCache = new List <DomainUpkFile>();

            foreach (DomainUpkFile file in upkFiles)
            {
                FileViewEntity fileEntity = viewModel.Files.SingleOrDefault(fe => fe.Filename == file.Filename) ?? mapper.Map <FileViewEntity>(file);

                message.Current++;
                message.StatusText = Path.Combine(settings.PathToGame, file.GameFilename);

                messenger.Send(message);

                DomainExportVersion bestVersion = file.GetCurrentExports() ?? new DomainExportVersion {
                    Versions = new List <DomainVersion>()
                };

                if (bestVersion.Versions.Contains(version))
                {
                    //
                    // This should never happen.  Toss an error to the ui to track it.
                    //
                    messenger.Send(new ApplicationErrorMessage {
                        HeaderText = "Odd Situation", ErrorMessage = $"Tried to scan a file, but the current version was already accounted for. {file.GameFilename} {version}/{locale}", OpenErrorWindow = true
                    });

                    continue;
                }

                if (bestVersion.Filesize == file.Filesize)
                {
                    bestVersion.Versions.Add(version);

                    if (fileEntity.ExportTypes == null || !fileEntity.ExportTypes.Any())
                    {
                        fileEntity.ExportTypes = new ObservableCollection <string>(bestVersion.Types.Select(t => t.Name));
                    }
                }
                else
                {
                    await scanUpkFile(fileEntity, file);

                    List <DomainExportType> exports = new List <DomainExportType>();

                    foreach (string type in file.Header.ExportTable.Select(e => e.TypeReferenceNameIndex.Name).Distinct().OrderBy(s => s))
                    {
                        exports.Add(new DomainExportType {
                            Name        = type,
                            ExportNames = file.Header.ExportTable.Where(e => e.TypeReferenceNameIndex.Name == type).Select(e => e.NameTableIndex.Name).Distinct().OrderBy(s => s).ToList()
                        });
                    }

                    file.Exports.Add(new DomainExportVersion {
                        Versions = new List <DomainVersion> {
                            version
                        }, Locale = locale, Filesize = file.Header.FileSize, Types = exports
                    });

                    fileEntity.FileSize    = file.Header.FileSize;
                    fileEntity.ExportTypes = new ObservableCollection <string>(exports.Select(e => e.Name));

                    file.Header = null;
                }

                string path = Path.GetDirectoryName(file.GameFilename);

                if (path != null && path.ToLowerInvariant().EndsWith("cookedpc"))
                {
                    if (!menuViewModel.IsOfflineMode)
                    {
                        saveCache.Add(file);
                    }

                    if (saveCache.Count == 50)
                    {
                        remoteRepository.SaveUpkFile(saveCache.ToList()).FireAndForget();

                        saveCache.Clear();
                    }
                }
            }

            if (saveCache.Any())
            {
                remoteRepository.SaveUpkFile(saveCache.ToList()).FireAndForget();
            }

            message.IsComplete = true;

            messenger.Send(message);

            isScanInProgress = false;
        }
        private async Task loadAllFiles()
        {
            isLoadInProgress = true;

            selectedFile = null;

            notesViewModel.SelectedFile = null;

            messenger.Send(new FileLoadingMessage());

            allFileEntities.ForEach(fe => fe.PropertyChanged -= onFileEntityViewModelChanged);

            allFileEntities.Clear();

            allFiles.Clear();

            viewModel.Files.Clear();

            if (String.IsNullOrEmpty(settings.PathToGame))
            {
                return;
            }

            LoadProgressMessage progress = new LoadProgressMessage {
                Text = "Loading Game Files..."
            };

            messenger.Send(progress);

            try {
                version = await repository.GetGameVersion(settings.PathToGame);
            }
            catch (FileNotFoundException) {
                messenger.Send(new MessageBoxDialogMessage {
                    Header = "Game Version File Not Found", Message = "The ..\\bin\\Version.ini file could not be found.\n\nPlease ensure your settings are pointed to the 'contents' directory.", HasCancel = false
                });

                progress.IsComplete = true;

                messenger.Send(progress);

                isLoadInProgress = false;

                return;
            }

            try {
                locale = await repository.GetGameLocale(settings.PathToGame);
            }
            catch (FileNotFoundException) {
                locale = CultureInfo.CurrentCulture.EnglishName.ToLowerInvariant();
            }

            List <DomainUpkFile> localFiles = await loadGameFiles();

            if (!localFiles.Any())
            {
                progress.IsComplete = true;

                messenger.Send(progress);

                isLoadInProgress = false;

                return;
            }

            localFiles.ForEach(f => f.CurrentVersion = version);

            List <DomainUpkFile> mods = (from row in localFiles
                                         let path = Path.GetDirectoryName(row.GameFilename)
                                                    where path != null &&
                                                    !path.EndsWith("CookedPC", StringComparison.CurrentCultureIgnoreCase)
                                                    select row).ToList();

            localFiles.RemoveAll(f => mods.Contains(f));

            progress.Text = "Loading Remote Database...";

            messenger.Send(progress);

            List <DomainUpkFile> remoteFiles = new List <DomainUpkFile>();

            string message = "No files returned from repository.";

            CancellationToken token = resetToken(ref remoteTokenSource);

            bool loadError = false;

            try {
                if (!menuViewModel.IsOfflineMode)
                {
                    remoteFiles = await remoteRepository.LoadUpkFiles(token);
                }
            }
            catch (Exception ex) {
                message = ex.Message;

                remoteFiles = new List <DomainUpkFile>();

                loadError = true;
            }

            if ((loadError || token.IsCancellationRequested) && !remoteFiles.Any())
            {
                if (loadError)
                {
                    messenger.Send(new MessageBoxDialogMessage {
                        Header = "Error Received from Remote Database", Message = $"The remote database returned an error.  Please try again in a few minutes.\n\n{message}\n\nThe program will continue using local files only.  Saving of file notes will be disabled.", HasCancel = false
                    });
                }

                progress.IsLocalMode = true;

                menuViewModel.IsOfflineMode = true;

                viewModel.IsShowFilesWithType = false;
            }

            remoteFiles.ForEach(f => {
                f.CurrentVersion = version;
                f.CurrentLocale  = locale;
            });

            List <DomainUpkFile> matches = (from row1 in localFiles
                                            join row2 in remoteFiles on new { row1.ContentsRoot, row1.Package } equals new { row2.ContentsRoot, row2.Package }
                                            where row2.Exports.Any(f => f.Versions.Contains(version) && f.Locale == locale && f.Filesize == row1.Filesize)
                                            let a = row2.GameFilename = row1.GameFilename
                                                                        select row2).ToList();

            if (matches.Any())
            {
                allFiles.AddRange(matches.OrderBy(f => f.Filename));
            }

            List <DomainUpkFile> changes = (from row1 in localFiles
                                            join row2 in remoteFiles on new { row1.ContentsRoot, row1.Package } equals new { row2.ContentsRoot, row2.Package }
                                            where row2.Exports.All(f => !f.Versions.Contains(version) || f.Locale != locale)
                                            let a = row2.GameFilename = row1.GameFilename
                                                                        select row2).ToList();

            if (changes.Any())
            {
                allFiles.AddRange(changes.OrderBy(f => f.Filename));

                allFiles.Sort(domainUpkfileComparison);

                await scanUpkFiles(changes);
            }

            List <DomainUpkFile> adds = (from row1 in localFiles
                                         join row2 in remoteFiles on new { row1.ContentsRoot, row1.Package } equals new { row2.ContentsRoot, row2.Package } into fileGroup
                                         from sub  in fileGroup.DefaultIfEmpty()
                                         where sub == null
                                         select row1).ToList();

            if (adds.Any())
            {
                allFiles.AddRange(adds.OrderBy(f => f.Filename));

                allFiles.Sort(domainUpkfileComparison);

                if (!menuViewModel.IsOfflineMode)
                {
                    await scanUpkFiles(adds);
                }
                else
                {
                    adds.ForEach(f => f.Id = Guid.NewGuid().ToString());
                }
            }

            viewModel.AllTypes = menuViewModel.IsOfflineMode ? new ObservableCollection <string>() : new ObservableCollection <string>(allFiles.SelectMany(f => f.GetCurrentExports().Types.Select(e => e.Name)).Distinct().OrderBy(s => s));

            allFiles.ForEach(f => { f.ModdedFiles.AddRange(mods.Where(mf => Path.GetFileName(mf.GameFilename) == Path.GetFileName(f.GameFilename) &&
                                                                      (Path.GetDirectoryName(mf.GameFilename) ?? String.Empty).StartsWith(Path.GetDirectoryName(f.GameFilename) ?? String.Empty))); });

            allFileEntities.AddRange(mapper.Map <List <FileViewEntity> >(allFiles));

            allFileEntities.ForEach(fe => fe.PropertyChanged += onFileEntityViewModelChanged);

            showFileTypes();

            progress.IsComplete = true;

            messenger.Send(progress);

            messenger.Send(new FileListingLoadedMessage {
                Allfiles = allFiles
            });

            isLoadInProgress = false;
        }
Beispiel #9
0
        private async Task scanUpkFiles(List <DomainUpkFile> upkFiles)
        {
            isScanInProgress = true;

            LoadProgressMessage message = new LoadProgressMessage {
                Text = "Scanning UPK Files", Current = 0, Total = upkFiles.Count
            };

            List <DomainUpkFile> saveCache = new List <DomainUpkFile>();

            foreach (DomainUpkFile file in upkFiles)
            {
                FileViewEntity fileEntity = viewModel.Files.SingleOrDefault(fe => fe.Filename == file.Filename) ?? mapper.Map <FileViewEntity>(file);

                message.Current++;
                message.StatusText = Path.Combine(settings.PathToGame, file.GameFilename);

                messenger.Send(message);

                await scanUpkFile(fileEntity, file);

                file.FileSize = file.Header.FileSize;

                List <DomainExportType> exports = new List <DomainExportType>();

                foreach (string type in file.Header.ExportTable.Select(e => e.TypeReferenceNameIndex.Name).Distinct().OrderBy(s => s))
                {
                    exports.Add(new DomainExportType {
                        Name        = type,
                        ExportNames = file.Header.ExportTable.Where(e => e.TypeReferenceNameIndex.Name == type).Select(e => e.NameTableIndex.Name).Distinct().OrderBy(s => s).ToList()
                    });
                }

                file.Exports.Where(e => e.Version == version).ToList().ForEach(e => file.Exports.Remove(e));

                file.Exports.Add(new DomainExportVersion {
                    Version = version, Types = exports
                });

                fileEntity.FileSize    = file.Header.FileSize;
                fileEntity.ExportTypes = new ObservableCollection <string>(exports.Select(e => e.Name));

                file.Header = null;

                string path = Path.GetDirectoryName(file.GameFilename);

                if (path != null && path.ToLowerInvariant().EndsWith("cookedpc"))
                {
                    if (!menuViewModel.IsOfflineMode)
                    {
                        saveCache.Add(file);
                    }

                    if (saveCache.Count == 50)
                    {
                        remoteRepository.SaveUpkFile(saveCache).FireAndForget();

                        saveCache.Clear();
                    }
                }
            }

            if (saveCache.Any())
            {
                remoteRepository.SaveUpkFile(saveCache).FireAndForget();
            }

            message.IsComplete = true;

            messenger.Send(message);

            isScanInProgress = false;
        }
        private async Task loadAllFiles()
        {
            messenger.Send(new FileLoadingMessage());

            allFileEntities.ForEach(fe => fe.PropertyChanged -= onFileEntityViewModelChanged);

            allFileEntities.Clear();

            allFiles.Clear();

            viewModel.Files.Clear();

            if (String.IsNullOrEmpty(settings.PathToGame))
            {
                return;
            }

            LoadProgressMessage progress = new LoadProgressMessage {
                Text = "Loading Game Files..."
            };

            messenger.Send(progress);

            try {
                version = await repository.GetGameVersion(settings.PathToGame);
            }
            catch (FileNotFoundException) {
                messenger.Send(new MessageBoxDialogMessage {
                    Header = "Game Version File Not Found", Message = "The VersionInfo_BnS*.ini file could not be found.\n\nPlease ensure your settings are pointed to the 'contents' directory.", HasCancel = false
                });

                progress.IsComplete = true;

                messenger.Send(progress);

                return;
            }

            List <DomainUpkFile> localFiles = await loadGameFiles();

            if (!localFiles.Any())
            {
                progress.IsComplete = true;

                messenger.Send(progress);

                return;
            }

            List <DomainUpkFile> mods = (from row in localFiles
                                         let path = Path.GetDirectoryName(row.GameFilename)
                                                    where path != null &&
                                                    !path.EndsWith("CookedPC", StringComparison.CurrentCultureIgnoreCase)
                                                    select row).ToList();

            localFiles.RemoveAll(f => mods.Contains(f));

            progress.Text = "Loading Remote Database...";

            messenger.Send(progress);

            List <DomainUpkFile> remoteFiles;

            try {
                remoteFiles = await remoteRepository.LoadUpkFiles();
            }
            catch (Exception ex) {
                messenger.Send(new MessageBoxDialogMessage {
                    Header = "Error Received from Remote Database", Message = $"The remote database returned an error.  Please try again in a few minutes.\n\n{ex.Message}", HasCancel = false
                });

                progress.IsComplete = true;

                messenger.Send(progress);

                return;
            }

            List <DomainUpkFile> matches = (from row1 in localFiles
                                            join row2 in remoteFiles on new { row1.ContentsRoot, row1.Package } equals new { row2.ContentsRoot, row2.Package }
                                            where row1.FileSize == row2.FileSize
                                            let a = row2.GameFilename = row1.GameFilename
                                                                        select row2).ToList();

            if (matches.Any())
            {
                allFiles.AddRange(matches.OrderBy(f => f.Filename));
            }

            List <DomainUpkFile> changes = (from row1 in localFiles
                                            join row2 in remoteFiles on new { row1.ContentsRoot, row1.Package } equals new { row2.ContentsRoot, row2.Package }
                                            where row1.FileSize != row2.FileSize
                                            let a = row2.GameFilename = row1.GameFilename
                                                                        select row2).ToList();

            if (changes.Any())
            {
                allFiles.AddRange(changes.OrderBy(f => f.Filename));

                allFiles.Sort(domainUpkfileComparison);

                await scanUpkFiles(changes);
            }

            List <DomainUpkFile> adds = (from row1 in localFiles
                                         join row2 in remoteFiles on new { row1.ContentsRoot, row1.Package } equals new { row2.ContentsRoot, row2.Package } into fileGroup
                                         from sub  in fileGroup.DefaultIfEmpty()
                                         where sub == null
                                         select row1).ToList();

            if (adds.Any())
            {
                allFiles.AddRange(adds.OrderBy(f => f.Filename));

                allFiles.Sort(domainUpkfileComparison);

                await scanUpkFiles(adds);
            }

            viewModel.AllTypes = new ObservableCollection <string>(allFiles.SelectMany(f => f.GetBestExports(version).Select(e => e.Name)).Distinct().OrderBy(s => s));

            // ReSharper disable once PossibleNullReferenceException
            allFiles.ForEach(f => { f.ModdedFiles.AddRange(mods.Where(mf => Path.GetFileName(mf.GameFilename) == Path.GetFileName(f.GameFilename) &&
                                                                      Path.GetDirectoryName(mf.GameFilename).StartsWith(Path.GetDirectoryName(f.GameFilename)))); });

            allFileEntities.AddRange(mapper.Map <List <FileViewEntity> >(allFiles));

            allFileEntities.ForEach(fe => fe.PropertyChanged += onFileEntityViewModelChanged);

            showFileTypes();

            progress.IsComplete = true;

            messenger.Send(progress);

            messenger.Send(new FileListingLoadedMessage {
                Allfiles = allFiles
            });
        }