private void Deployment_BackgroundThread(object sender, DoWorkEventArgs e) { var referencedFiles = ModBeingDeployed.GetAllRelativeReferences(); string archivePath = e.Argument as string; //Key is in-archive path, value is on disk path var archiveMapping = new Dictionary <string, string>(); SortedSet <string> directories = new SortedSet <string>(); foreach (var file in referencedFiles) { var path = Path.Combine(ModBeingDeployed.ModPath, file); var directory = Directory.GetParent(path).FullName; if (directory.Length <= ModBeingDeployed.ModPath.Length) { continue; //root file or directory. } directory = directory.Substring(ModBeingDeployed.ModPath.Length + 1); //nested folders with no folders var relativeFolders = directory.Split('\\'); string buildingFolderList = ""; foreach (var relativeFolder in relativeFolders) { if (buildingFolderList != "") { buildingFolderList += @"\\"; } buildingFolderList += relativeFolder; if (directories.Add(buildingFolderList)) { archiveMapping[buildingFolderList] = null; } } } archiveMapping.AddRange(referencedFiles.ToDictionary(x => x, x => Path.Combine(ModBeingDeployed.ModPath, x))); var compressor = new SevenZip.SevenZipCompressor(); //compressor.CompressionLevel = CompressionLevel.Ultra; compressor.CustomParameters.Add(@"s", @"on"); if (!MultithreadedCompression) { compressor.CustomParameters.Add(@"mt", @"off"); } compressor.CustomParameters.Add(@"yx", @"9"); //compressor.CustomParameters.Add("x", "9"); compressor.CustomParameters.Add(@"d", @"28"); string currentDeploymentStep = M3L.GetString(M3L.string_mod); compressor.Progressing += (a, b) => { //Debug.WriteLine(b.AmountCompleted + "/" + b.TotalAmount); ProgressMax = b.TotalAmount; ProgressValue = b.AmountCompleted; var now = DateTime.Now; if ((now - lastPercentUpdateTime).Milliseconds > ModInstaller.PERCENT_REFRESH_COOLDOWN) { //Don't update UI too often. Once per second is enough. string percent = (ProgressValue * 100.0 / ProgressMax).ToString(@"0.00"); OperationText = $@"[{currentDeploymentStep}] {M3L.GetString(M3L.string_deploymentInProgress)} {percent}%"; lastPercentUpdateTime = now; } //Debug.WriteLine(ProgressValue + "/" + ProgressMax); }; compressor.FileCompressionStarted += (a, b) => { Debug.WriteLine(b.FileName); }; compressor.CompressFileDictionary(archiveMapping, archivePath); compressor.CustomParameters.Clear(); //remove custom params as it seems to force LZMA compressor.CompressionMode = CompressionMode.Append; compressor.CompressionLevel = CompressionLevel.None; currentDeploymentStep = @"moddesc.ini"; compressor.CompressFiles(archivePath, new string[] { Path.Combine(ModBeingDeployed.ModPath, @"moddesc.ini") }); OperationText = M3L.GetString(M3L.string_deploymentSucceeded); Utilities.HighlightInExplorer(archivePath); }
private void CheckModForTFCCompactability(DeploymentChecklistItem item) { // if (ModBeingDeployed.Game >= Mod.MEGame.ME2) //{ bool hasError = false; item.HasError = false; item.ItemText = M3L.GetString(M3L.string_checkingTexturesInMod); var referencedFiles = ModBeingDeployed.GetAllRelativeReferences().Select(x => Path.Combine(ModBeingDeployed.ModPath, x)).ToList(); int numChecked = 0; GameTarget validationTarget = mainWindow.InstallationTargets.FirstOrDefault(x => x.Game == ModBeingDeployed.Game); var errors = new List <string>(); foreach (var f in referencedFiles) { if (_closed) { return; } numChecked++; item.ItemText = $@"{M3L.GetString(M3L.string_checkingTexturesInMod)} [{numChecked}/{referencedFiles.Count}]"; if (f.RepresentsPackageFilePath()) { Log.Information(@"Checking file for broken textures: " + f); var package = MEPackageHandler.OpenMEPackage(f); var textures = package.Exports.Where(x => x.IsTexture()).ToList(); foreach (var texture in textures) { if (_closed) { return; } var cache = texture.GetProperty <NameProperty>(@"TextureFileCacheName"); if (cache != null) { if (!VanillaDatabaseService.IsBasegameTFCName(cache.Value, ModBeingDeployed.Game)) { var mips = Texture2D.GetTexture2DMipInfos(texture, cache.Value); Texture2D tex = new Texture2D(texture); try { tex.GetImageBytesForMip(tex.GetTopMip(), validationTarget, false); //use active target } catch (Exception e) { Log.Information(@"Found broken texture: " + texture.GetInstancedFullPath); hasError = true; item.Icon = FontAwesomeIcon.TimesCircle; item.Foreground = Brushes.Red; item.Spinning = false; errors.Add(M3L.GetString(M3L.string_interp_couldNotLoadTextureData, texture.FileRef.FilePath, texture.GetInstancedFullPath, e.Message)); } } } } } } if (!hasError) { item.Foreground = Brushes.Green; item.Icon = FontAwesomeIcon.CheckCircle; item.ItemText = M3L.GetString(M3L.string_noBrokenTexturesWereFound); item.ToolTip = M3L.GetString(M3L.string_validationOK); } else { item.Errors = errors; item.ItemText = M3L.GetString(M3L.string_textureIssuesWereDetected); item.ToolTip = M3L.GetString(M3L.string_validationFailed); } item.HasError = hasError; }
private void CheckModSFARs(DeploymentChecklistItem item) { bool hasError = false; item.HasError = false; item.ItemText = M3L.GetString(M3L.string_checkingSFARFilesSizes); var referencedFiles = ModBeingDeployed.GetAllRelativeReferences().Select(x => Path.Combine(ModBeingDeployed.ModPath, x)).ToList(); int numChecked = 0; GameTarget validationTarget = mainWindow.InstallationTargets.FirstOrDefault(x => x.Game == ModBeingDeployed.Game); List <string> gameFiles = MEDirectories.EnumerateGameFiles(validationTarget.Game, validationTarget.TargetPath); var errors = new List <string>(); Dictionary <string, MemoryStream> cachedAudio = new Dictionary <string, MemoryStream>(); bool hasSFARs = false; foreach (var f in referencedFiles) { if (_closed) { return; } if (Path.GetExtension(f) == @".sfar") { hasSFARs = true; if (new FileInfo(f).Length != 32) { { hasError = true; item.Icon = FontAwesomeIcon.TimesCircle; item.Foreground = Brushes.Red; item.Spinning = false; errors.Add(f); } } } } if (!hasSFARs) { item.Foreground = Brushes.Green; item.Icon = FontAwesomeIcon.CheckCircle; item.ItemText = M3L.GetString(M3L.string_modDoesNotUseSFARs); item.ToolTip = M3L.GetString(M3L.string_validationOK); } else { if (!hasError) { item.Foreground = Brushes.Green; item.Icon = FontAwesomeIcon.CheckCircle; item.ItemText = M3L.GetString(M3L.string_noSFARSizeIssuesWereDetected); item.ToolTip = M3L.GetString(M3L.string_validationOK); } else { item.Errors = errors; item.ItemText = M3L.GetString(M3L.string_someSFARSizesAreTheIncorrectSize); item.ToolTip = M3L.GetString(M3L.string_validationFailed); } item.HasError = hasError; } }
private void CheckModForAFCCompactability(DeploymentChecklistItem item) { bool hasError = false; item.HasError = false; item.ItemText = M3L.GetString(M3L.string_checkingAudioReferencesInMod); var referencedFiles = ModBeingDeployed.GetAllRelativeReferences().Select(x => Path.Combine(ModBeingDeployed.ModPath, x)).ToList(); int numChecked = 0; GameTarget validationTarget = mainWindow.InstallationTargets.FirstOrDefault(x => x.Game == ModBeingDeployed.Game); List <string> gameFiles = MEDirectories.EnumerateGameFiles(validationTarget.Game, validationTarget.TargetPath); var errors = new List <string>(); Dictionary <string, MemoryStream> cachedAudio = new Dictionary <string, MemoryStream>(); foreach (var f in referencedFiles) { if (_closed) { return; } numChecked++; item.ItemText = $@"{M3L.GetString(M3L.string_checkingAudioReferencesInMod)} [{numChecked}/{referencedFiles.Count}]"; if (f.RepresentsPackageFilePath()) { var package = MEPackageHandler.OpenMEPackage(f); var wwiseStreams = package.Exports.Where(x => x.ClassName == @"WwiseStream" && !x.IsDefaultObject).ToList(); foreach (var wwisestream in wwiseStreams) { if (_closed) { return; } //Check each reference. var afcNameProp = wwisestream.GetProperty <NameProperty>(@"Filename"); if (afcNameProp != null) { string afcNameWithExtension = afcNameProp + @".afc"; int audioSize = BitConverter.ToInt32(wwisestream.Data, wwisestream.Data.Length - 8); int audioOffset = BitConverter.ToInt32(wwisestream.Data, wwisestream.Data.Length - 4); string afcPath = null; Stream audioStream = null; var localDirectoryAFCPath = Path.Combine(Path.GetDirectoryName(wwisestream.FileRef.FilePath), afcNameWithExtension); bool isInOfficialArea = false; if (File.Exists(localDirectoryAFCPath)) { //local afc afcPath = localDirectoryAFCPath; } else { //Check game var fullPath = gameFiles.FirstOrDefault(x => Path.GetFileName(x).Equals(afcNameWithExtension, StringComparison.InvariantCultureIgnoreCase)); if (fullPath != null) { afcPath = fullPath; isInOfficialArea = MEDirectories.IsInBasegame(afcPath, validationTarget) || MEDirectories.IsInOfficialDLC(afcPath, validationTarget); } else if (cachedAudio.TryGetValue(afcNameProp.Value.Name, out var cachedAudioStream)) { audioStream = cachedAudioStream; //isInOfficialArea = true; //cached from vanilla SFAR } else if (MEDirectories.OfficialDLC(validationTarget.Game).Any(x => afcNameProp.Value.Name.StartsWith(x))) { var dlcName = afcNameProp.Value.Name.Substring(0, afcNameProp.Value.Name.LastIndexOf(@"_", StringComparison.InvariantCultureIgnoreCase)); var audio = VanillaDatabaseService.FetchFileFromVanillaSFAR(validationTarget, dlcName, afcNameWithExtension); if (audio != null) { cachedAudio[afcNameProp.Value.Name] = audio; } audioStream = audio; //isInOfficialArea = true; as this is in a vanilla SFAR we don't test against this since it will be correct. continue; } else { hasError = true; item.Icon = FontAwesomeIcon.TimesCircle; item.Foreground = Brushes.Red; item.Spinning = false; errors.Add(M3L.GetString(M3L.string_interp_couldNotFindReferencedAFC, wwisestream.FileRef.FilePath, wwisestream.GetInstancedFullPath, afcNameProp.ToString())); continue; } } if (afcPath != null) { audioStream = new FileStream(afcPath, FileMode.Open); } try { audioStream.Seek(audioOffset, SeekOrigin.Begin); if (audioStream.ReadStringASCIINull(4) != @"RIFF") { hasError = true; item.Icon = FontAwesomeIcon.TimesCircle; item.Foreground = Brushes.Red; item.Spinning = false; errors.Add(M3L.GetString(M3L.string_interp_invalidAudioPointer, wwisestream.FileRef.FilePath, wwisestream.GetInstancedFullPath)); if (audioStream is FileStream) { audioStream.Close(); } continue; } //attempt to seek audio length. audioStream.Seek(audioSize + 4, SeekOrigin.Current); //Check if this file is in basegame if (isInOfficialArea) { //Verify offset is not greater than vanilla size var vanillaInfo = VanillaDatabaseService.GetVanillaFileInfo(validationTarget, afcPath.Substring(validationTarget.TargetPath.Length + 1)); if (vanillaInfo == null) { Crashes.TrackError(new Exception($@"Vanilla information was null when performing vanilla file check for {afcPath.Substring(validationTarget.TargetPath.Length + 1)}")); } if (audioOffset >= vanillaInfo[0].size) { hasError = true; item.Icon = FontAwesomeIcon.TimesCircle; item.Foreground = Brushes.Red; item.Spinning = false; errors.Add(M3L.GetString(M3L.string_interp_audioStoredInOfficialAFC, wwisestream.FileRef.FilePath, wwisestream.GetInstancedFullPath)); } } if (audioStream is FileStream) { audioStream.Close(); } } catch (Exception e) { hasError = true; item.Icon = FontAwesomeIcon.TimesCircle; item.Foreground = Brushes.Red; item.Spinning = false; if (audioStream is FileStream) { audioStream.Close(); } errors.Add(M3L.GetString(M3L.string_errorValidatingAudioReference, wwisestream.FileRef.FilePath, wwisestream.GetInstancedFullPath, e.Message)); continue; } } } } } if (!hasError) { item.Foreground = Brushes.Green; item.Icon = FontAwesomeIcon.CheckCircle; item.ItemText = M3L.GetString(M3L.string_noAudioIssuesWereDetected); item.ToolTip = M3L.GetString(M3L.string_validationOK); } else { item.Errors = errors; item.ItemText = M3L.GetString(M3L.string_audioIssuesWereDetected); item.ToolTip = M3L.GetString(M3L.string_validationFailed); } item.HasError = hasError; cachedAudio.Clear(); }
private void CheckModForTFCCompactability(DeploymentChecklistItem item) { // if (ModBeingDeployed.Game >= Mod.MEGame.ME2) //{ bool hasError = false; item.HasError = false; item.ItemText = "Checking textures in mod"; var referencedFiles = ModBeingDeployed.GetAllRelativeReferences().Select(x => Path.Combine(ModBeingDeployed.ModPath, x)).ToList(); int numChecked = 0; GameTarget validationTarget = mainWindow.InstallationTargets.FirstOrDefault(x => x.Game == ModBeingDeployed.Game); var errors = new List <string>(); foreach (var f in referencedFiles) { if (_closed) { return; } numChecked++; item.ItemText = $"Checking textures in mod [{numChecked}/{referencedFiles.Count}]"; if (f.RepresentsPackageFilePath()) { var package = MEPackageHandler.OpenMEPackage(f); var textures = package.Exports.Where(x => x.IsTexture()).ToList(); foreach (var texture in textures) { if (_closed) { return; } var cache = texture.GetProperty <NameProperty>("TextureFileCacheName"); if (cache != null) { if (!VanillaDatabaseService.IsBasegameTFCName(cache.Value, ModBeingDeployed.Game)) { var mips = Texture2D.GetTexture2DMipInfos(texture, cache.Value); Texture2D tex = new Texture2D(texture); try { tex.GetImageBytesForMip(tex.GetTopMip(), validationTarget, false); //use active target } catch (Exception e) { hasError = true; item.Icon = FontAwesomeIcon.TimesCircle; item.Foreground = Brushes.Red; item.Spinning = false; errors.Add($"{texture.FileRef.FilePath} - {texture.GetInstancedFullPath}: Could not load texture data: {e.Message}"); } } } } } } if (!hasError) { item.Foreground = Brushes.Green; item.Icon = FontAwesomeIcon.CheckCircle; item.ItemText = "No broken textures were found"; item.ToolTip = "Validation passed"; } else { item.Errors = errors; item.ItemText = "Texture issues were detected"; item.ToolTip = "Validation failed"; } item.HasError = hasError; //} //} else //{ // item.Foreground = Brushes.Green; // item.Icon = FontAwesomeIcon.CheckCircle; // item.ItemText = "Textures are not "; // item.ToolTip = "Validation passed"; //} }