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 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);

        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 (!isLocalMode) 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() {
      isLoadInProgress = true;

      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;
      }

      List<DomainUpkFile> localFiles = await loadGameFiles();

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

        messenger.Send(progress);

        isLoadInProgress = false;

        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}\n\nThe program will continue using local files only.  Saving of file notes will be disabled.", HasCancel = false });

        progress.IsLocalMode = true;

        isLocalMode = true;

        viewModel.IsShowFilesWithType = false;

        remoteFiles = new List<DomainUpkFile>();
      }

      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);

        if (!isLocalMode) await scanUpkFiles(adds);
        else adds.ForEach(f => f.CurrentVersion = version);
      }

      viewModel.AllTypes = isLocalMode ? new ObservableCollection<string>() : 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 });

      isLoadInProgress = false;
    }
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;

          DdsSaveConfig config = new DdsSaveConfig(FileFormat.Unknown, 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 };

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

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

      messenger.Send(message);
    }
Beispiel #6
0
    private void onLoadProgress(LoadProgressMessage message) {
      if (!message.IsComplete) return;

      isLocalMode = message.IsLocalMode;
    }
    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);
    }