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(); }
public static byte[] GetTextureData(Texture2DMipInfo mipToLoad, GameTarget target, bool decompress = true, List <string> additionalTFCs = null) { var imagebytes = new byte[decompress ? mipToLoad.uncompressedSize : mipToLoad.compressedSize]; //Debug.WriteLine("getting texture data for " + mipToLoad.Export.FullPath); if (mipToLoad.storageType == StorageTypes.pccUnc) { Buffer.BlockCopy(mipToLoad.Export.Data, mipToLoad.localExportOffset, imagebytes, 0, mipToLoad.uncompressedSize); } else if (mipToLoad.storageType == StorageTypes.pccLZO || mipToLoad.storageType == StorageTypes.pccZlib) { if (decompress) { try { TextureCompression.DecompressTexture(imagebytes, new MemoryStream(mipToLoad.Export.Data, mipToLoad.localExportOffset, mipToLoad.compressedSize), mipToLoad.storageType, mipToLoad.uncompressedSize, mipToLoad.compressedSize); } catch (Exception e) { throw new Exception($"{e.Message}\nStorageType: {mipToLoad.storageType}\n"); } } else { Buffer.BlockCopy(mipToLoad.Export.Data, mipToLoad.localExportOffset, imagebytes, 0, mipToLoad.compressedSize); } } else if (mipToLoad.storageType == StorageTypes.extUnc || mipToLoad.storageType == StorageTypes.extLZO || mipToLoad.storageType == StorageTypes.extZlib) { string filename = null; List <string> loadedFiles = MEDirectories.EnumerateGameFiles(target.Game, target.TargetPath); if (mipToLoad.Export.Game == Mod.MEGame.ME1) { var fullPath = loadedFiles.FirstOrDefault(x => Path.GetFileName(x).Equals(mipToLoad.TextureCacheName, StringComparison.InvariantCultureIgnoreCase)); if (fullPath != null) { filename = fullPath; } else { throw new FileNotFoundException($"Externally referenced texture file not found in game: {mipToLoad.TextureCacheName}."); } } else { string archive = mipToLoad.TextureCacheName + ".tfc"; var localDirectoryTFCPath = Path.Combine(Path.GetDirectoryName(mipToLoad.Export.FileRef.FilePath), archive); if (File.Exists(localDirectoryTFCPath)) { filename = localDirectoryTFCPath; } else if (additionalTFCs != null && additionalTFCs.Any(x => Path.GetFileName(x).Equals(archive, StringComparison.InvariantCultureIgnoreCase))) { filename = additionalTFCs.First(x => Path.GetFileName(x).Equals(archive, StringComparison.InvariantCultureIgnoreCase)); } else { var tfcs = loadedFiles.Where(x => x.EndsWith(@".tfc")).ToList(); var fullPath = loadedFiles.FirstOrDefault(x => Path.GetFileName(x).Equals(archive, StringComparison.InvariantCultureIgnoreCase)); if (fullPath != null) { filename = fullPath; } else { throw new FileNotFoundException($@"Externally referenced texture cache not found: {archive}."); } } } //exceptions above will prevent filename from being null here try { using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read)) { try { fs.Seek(mipToLoad.externalOffset, SeekOrigin.Begin); if (mipToLoad.storageType == StorageTypes.extLZO || mipToLoad.storageType == StorageTypes.extZlib) { if (decompress) { using (MemoryStream tmpStream = new MemoryStream(fs.ReadToBuffer(mipToLoad.compressedSize))) { try { TextureCompression.DecompressTexture(imagebytes, tmpStream, mipToLoad.storageType, mipToLoad.uncompressedSize, mipToLoad.compressedSize); } catch (Exception e) { throw new Exception(e.Message + "\n" + "File: " + filename + "\n" + "StorageType: " + mipToLoad.storageType + "\n" + "External file offset: " + mipToLoad.externalOffset); } } } else { fs.Read(imagebytes, 0, mipToLoad.compressedSize); } } else { fs.Read(imagebytes, 0, mipToLoad.uncompressedSize); } } catch (Exception e) { throw new Exception(e.Message + "\n" + "File: " + filename + "\n" + "StorageType: " + mipToLoad.storageType + "\n" + "External file offset: " + mipToLoad.externalOffset); } } } catch (Exception e) { throw new Exception(e.Message + "\n" + "File: " + filename + "\n" + "StorageType: " + mipToLoad.storageType + "\n" + "External file offset: " + mipToLoad.externalOffset); } } return(imagebytes); }
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; } }
internal static List <string> EnumerateGameFiles(GameTarget validationTarget, Predicate <string> predicate = null) { return(MEDirectories.EnumerateGameFiles(validationTarget.Game, validationTarget.TargetPath, predicate: predicate)); }