public void CloseAllWithSave(bool forceZlib = false) { for (int i = 0; i < packages.Count; i++) { Package pkg = packages[i]; if (mainWindow != null) { mainWindow.updateStatusLabel2("Saving package " + (i + 1) + " of " + packages.Count); } if (_installer != null) { _installer.updateStatusStore("Saving packages " + (i * 100 / packages.Count) + "%"); } pkg.SaveToFile(forceZlib); pkg.Dispose(); } if (GameData.gameType == MeType.ME3_TYPE) { TOCBinFile.UpdateAllTOCBinFiles(); } if (mainWindow != null) { mainWindow.updateStatusLabel2(""); } packages.Clear(); }
public string PrepareListOfTextures(TexExplorer texEplorer, CachePackageMgr cachePackageMgr, MainWindow mainWindow, Installer installer, ref string log, bool force = false) { string errors = ""; treeScan = null; List <FoundTexture> textures = new List <FoundTexture>(); string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), Assembly.GetExecutingAssembly().GetName().Name); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } string filename = Path.Combine(path, "me" + (int)GameData.gameType + "map.bin"); if (force && File.Exists(filename)) { File.Delete(filename); } if (File.Exists(filename)) { using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.ReadWrite)) { uint tag = fs.ReadUInt32(); uint version = fs.ReadUInt32(); if (tag != TexExplorer.textureMapBinTag || version != TexExplorer.textureMapBinVersion) { if (mainWindow != null) { MessageBox.Show("Wrong " + filename + " file!"); mainWindow.updateStatusLabel(""); mainWindow.updateStatusLabel2(""); texEplorer.Close(); } fs.Close(); log += "Wrong " + filename + " file!" + Environment.NewLine; return("Wrong " + filename + " file!" + Environment.NewLine); } uint countTexture = fs.ReadUInt32(); for (int i = 0; i < countTexture; i++) { FoundTexture texture = new FoundTexture(); texture.name = fs.ReadStringASCIINull(); texture.crc = fs.ReadUInt32(); texture.packageName = fs.ReadStringASCIINull(); uint countPackages = fs.ReadUInt32(); texture.list = new List <MatchedTexture>(); for (int k = 0; k < countPackages; k++) { MatchedTexture matched = new MatchedTexture(); matched.exportID = fs.ReadInt32(); matched.path = fs.ReadStringASCIINull(); texture.list.Add(matched); } textures.Add(texture); } if (fs.Position < new FileInfo(filename).Length) { List <string> packages = new List <string>(); int numPackages = fs.ReadInt32(); for (int i = 0; i < numPackages; i++) { string pkgPath = fs.ReadStringASCIINull(); pkgPath = GameData.GamePath + pkgPath; packages.Add(pkgPath); } for (int i = 0; i < packages.Count; i++) { if (GameData.packageFiles.Find(s => s.Equals(packages[i], StringComparison.OrdinalIgnoreCase)) == null) { if (mainWindow != null) { MessageBox.Show("Detected removal of game files since last game data scan." + "\n\nYou need to restore the game to vanilla state and reinstall vanilla DLCs and DLC mods." + "\n\nThen from the main menu, select 'Remove Textures Scan File' and start Texture Manager again."); return(""); } else if (!force) { errors += "Detected removal of game files since last game data scan." + Environment.NewLine + Environment.NewLine + "You need to restore the game to vanilla state and reinstall vanilla DLCs and DLC mods."; return(""); } } } for (int i = 0; i < GameData.packageFiles.Count; i++) { if (packages.Find(s => s.Equals(GameData.packageFiles[i], StringComparison.OrdinalIgnoreCase)) == null) { if (mainWindow != null) { MessageBox.Show("Detected additional game files not present in latest game data scan." + "\n\nYou need to restore the game to vanilla state and reinstall vanilla DLCs and DLC mods." + "\n\nThen from the main menu, select 'Remove Textures Scan File' and start Texture Manager again."); return(""); } else if (!force) { errors += "Detected additional game files not present in latest game data scan." + Environment.NewLine + Environment.NewLine + "You need to restore the game to vanilla state and reinstall vanilla DLCs and DLC mods."; return(""); } } } } else { fs.SeekEnd(); fs.WriteInt32(GameData.packageFiles.Count); for (int i = 0; i < GameData.packageFiles.Count; i++) { fs.WriteStringASCIINull(GameData.RelativeGameData(GameData.packageFiles[i])); } } treeScan = textures; if (mainWindow != null) { mainWindow.updateStatusLabel(""); mainWindow.updateStatusLabel2(""); } return(errors); } } if (File.Exists(filename)) { File.Delete(filename); } if (Misc.detectBrokenMod(GameData.gameType)) { if (mainWindow != null) { MessageBox.Show("Detected ME1 Controller or/and Faster Elevators mod!\nMEM will not work properly due broken content in mod."); } return(""); } if (MipMaps.checkGameDataModded(cachePackageMgr)) { if (mainWindow != null) { MessageBox.Show("Detected modded game. Can not continue." + "\n\nYou need to restore the game to vanilla state and reinstall vanilla DLCs and DLC mods." + "\n\nThen start Texture Manager again."); return(""); } else if (!force) { errors += "Detected modded game. Can not continue." + Environment.NewLine + Environment.NewLine + "You need to restore the game to vanilla state and reinstall vanilla DLCs and DLC mods."; return(""); } } if (mainWindow != null) { DialogResult result = MessageBox.Show("Replacing textures and creating mods requires generating a map of the game's textures.\n" + "You only need to do it once.\n\n" + "IMPORTANT! Your game needs to be in vanilla state and have all original DLCs and DLC mods installed.\n\n" + "Are you sure you want to proceed?", "Textures mapping", MessageBoxButtons.YesNo); if (result == DialogResult.No) { texEplorer.Close(); return(""); } } GameData.packageFiles.Sort(); if (mainWindow != null) { Misc.startTimer(); } for (int i = 0; i < GameData.packageFiles.Count; i++) { if (mainWindow != null) { mainWindow.updateStatusLabel("Finding textures in package " + (i + 1) + " of " + GameData.packageFiles.Count + " - " + GameData.packageFiles[i]); } if (installer != null) { installer.updateStatusScan("Progress... " + (i * 100 / GameData.packageFiles.Count) + " % "); } errors += FindTextures(textures, GameData.packageFiles[i], cachePackageMgr, ref log); } using (FileStream fs = new FileStream(filename, FileMode.Create, FileAccess.Write)) { fs.WriteUInt32(TexExplorer.textureMapBinTag); fs.WriteUInt32(TexExplorer.textureMapBinVersion); fs.WriteInt32(textures.Count); for (int i = 0; i < textures.Count; i++) { fs.WriteStringASCIINull(textures[i].name); fs.WriteUInt32(textures[i].crc); fs.WriteStringASCIINull(textures[i].packageName); fs.WriteInt32(textures[i].list.Count); for (int k = 0; k < textures[i].list.Count; k++) { fs.WriteInt32(textures[i].list[k].exportID); fs.WriteStringASCIINull(textures[i].list[k].path); } } fs.WriteInt32(GameData.packageFiles.Count); for (int i = 0; i < GameData.packageFiles.Count; i++) { fs.WriteStringASCIINull(GameData.RelativeGameData(GameData.packageFiles[i])); } } if (mainWindow != null) { MipMaps mipmaps = new MipMaps(); if (GameData.gameType == MeType.ME1_TYPE) { errors += mipmaps.removeMipMapsME1(1, textures, null, mainWindow, null); errors += mipmaps.removeMipMapsME1(2, textures, null, mainWindow, null); } else { errors += mipmaps.removeMipMapsME2ME3(textures, null, mainWindow, null); } var time = Misc.stopTimer(); mainWindow.updateStatusLabel("Done. Process total time: " + Misc.getTimerFormat(time)); mainWindow.updateStatusLabel2(""); } treeScan = textures; return(errors); }
public void fullRePack(string inPath, string outPath, string DLCName, MainWindow mainWindow, Installer installer) { if (sfarFile != null) { throw new Exception(); } if (!Directory.Exists(inPath)) { throw new Exception("Directory not found: " + inPath); } List <byte[]> hashList = new List <byte[]>(); List <string> srcFilesList = Directory.GetFiles(inPath, "*.*", SearchOption.AllDirectories).ToList(); srcFilesList.RemoveAll(s => s.ToLowerInvariant().Contains("default.sfar")); using (FileStream outputFile = new FileStream(inPath + @"\TOC", FileMode.Create, FileAccess.Write)) { for (int i = 0; i < srcFilesList.Count(); i++) { int pos = srcFilesList[i].IndexOf("\\BIOGame\\DLC\\", StringComparison.OrdinalIgnoreCase); string filename = srcFilesList[i].Substring(pos).Replace('\\', '/'); hashList.Add(MD5.Create().ComputeHash(Encoding.ASCII.GetBytes(filename.ToLowerInvariant()))); outputFile.WriteStringASCII(filename + Environment.NewLine); } } hashList.Add(FileListHash); srcFilesList.Add(inPath + @"\TOC"); Directory.CreateDirectory(Path.GetDirectoryName(outPath)); using (FileStream outputFile = new FileStream(outPath, FileMode.Create, FileAccess.Write)) { long numBlockSizes = 0; int curBlockSizesIndex = 0; long dataOffset = HeaderSize + EntryHeaderSize * (srcFilesList.Count()); long sizesArrayOffset = dataOffset; for (int i = 0; i < srcFilesList.Count(); i++) { if (srcFilesList[i].EndsWith(".bik", StringComparison.OrdinalIgnoreCase) || srcFilesList[i].EndsWith(".afc", StringComparison.OrdinalIgnoreCase)) { continue; } long fileLen = new FileInfo(srcFilesList[i]).Length; long numBlocks = (fileLen + MaxBlockSize - 1) / MaxBlockSize; dataOffset += numBlocks * sizeof(ushort); numBlockSizes += numBlocks; } List <FileEntry> filesList = new List <FileEntry>(); ushort[] blockSizes = new ushort[numBlockSizes]; long curDataOffset = dataOffset; outputFile.JumpTo(dataOffset); for (int i = 0; i < srcFilesList.Count(); i++) { if (mainWindow != null) { mainWindow.updateStatusLabel2("File " + (i + 1) + " of " + srcFilesList.Count() + " - " + Path.GetFileName(srcFilesList[i])); } if (installer != null) { installer.updateStatusPrepare("Compressing DLC... " + (i + 1) + " of " + srcFilesList.Count); } FileEntry file = new FileEntry(); Stream inputFile = new FileStream(srcFilesList[i], FileMode.Open, FileAccess.Read); long fileLen = new FileInfo(srcFilesList[i]).Length; file.dataOffset = curDataOffset; file.uncomprSize = fileLen; file.filenameHash = hashList[i]; if (srcFilesList[i].EndsWith(".bik", StringComparison.OrdinalIgnoreCase) || srcFilesList[i].EndsWith(".afc", StringComparison.OrdinalIgnoreCase)) { outputFile.WriteFromStream(inputFile, fileLen); file.compressedBlockSizesIndex = -1; } else { List <byte[]> uncompressedBlockBuffers = new List <byte[]>(); List <byte[]> compressedBlockBuffers = new List <byte[]>(); file.compressedBlockSizesIndex = curBlockSizesIndex; file.numBlocks = (uint)((file.uncomprSize + MaxBlockSize - 1) / MaxBlockSize); for (int k = 0; k < file.numBlocks; k++) { long uncompressedBlockSize = MaxBlockSize; if (k == (file.numBlocks - 1)) // last block { uncompressedBlockSize = file.uncomprSize - (MaxBlockSize * k); } uncompressedBlockBuffers.Add(inputFile.ReadToBuffer((int)uncompressedBlockSize)); compressedBlockBuffers.Add(null); } Parallel.For(0, file.numBlocks, k => { compressedBlockBuffers[(int)k] = SevenZipHelper.LZMA.Compress(uncompressedBlockBuffers[(int)k], 9); if (compressedBlockBuffers[(int)k].Length == 0) { throw new Exception(); } }); for (int k = 0; k < file.numBlocks; k++, curBlockSizesIndex++) { if (compressedBlockBuffers[k].Length >= (int)MaxBlockSize) { outputFile.WriteFromBuffer(uncompressedBlockBuffers[k]); blockSizes[curBlockSizesIndex] = 0; } else if (compressedBlockBuffers[k].Length >= uncompressedBlockBuffers[k].Length) { outputFile.WriteFromBuffer(uncompressedBlockBuffers[k]); blockSizes[curBlockSizesIndex] = (ushort)uncompressedBlockBuffers[k].Length; } else { outputFile.WriteFromBuffer(compressedBlockBuffers[k]); blockSizes[curBlockSizesIndex] = (ushort)compressedBlockBuffers[k].Length; } } } curDataOffset = outputFile.Position; filesList.Add(file); inputFile.Close(); } if (blockSizes.Count() != curBlockSizesIndex) { throw new Exception(); } outputFile.SeekBegin(); outputFile.WriteUInt32(SfarTag); outputFile.WriteUInt32(SfarVersion); outputFile.WriteUInt32((uint)dataOffset); outputFile.WriteUInt32(HeaderSize); outputFile.WriteUInt32((uint)filesList.Count); outputFile.WriteUInt32((uint)sizesArrayOffset); outputFile.WriteUInt32((uint)MaxBlockSize); outputFile.WriteUInt32(LZMATag); filesList.Sort(new FileArrayComparer()); for (int i = 0; i < filesList.Count; i++) { outputFile.WriteFromBuffer(filesList[i].filenameHash); outputFile.WriteInt32(filesList[i].compressedBlockSizesIndex); outputFile.WriteUInt32((uint)filesList[i].uncomprSize); outputFile.WriteByte((byte)(filesList[i].uncomprSize >> 32)); outputFile.WriteUInt32((uint)filesList[i].dataOffset); outputFile.WriteByte((byte)(filesList[i].dataOffset >> 32)); } if (outputFile.Position != sizesArrayOffset) { throw new Exception(); } for (int i = 0; i < blockSizes.Count(); i++) { outputFile.WriteUInt16(blockSizes[i]); } if (outputFile.Position != dataOffset) { throw new Exception(); } } File.Delete(inPath + @"\TOC"); }
public string removeMipMapsME1(int phase, List <FoundTexture> textures, MainWindow mainWindow, Installer installer, bool ipc) { string errors = ""; int lastProgress = -1; List <RemoveMipsEntry> list = prepareListToRemove(textures); string path = @"\BioGame\CookedPC\testVolumeLight_VFX.upk"; for (int i = 0; i < list.Count; i++) { if (path == list[i].pkgPath) { continue; } if (installer != null) { installer.updateProgressStatus("Removing empty mipmaps " + ((list.Count * (phase - 1) + i + 1) * 100 / (list.Count * 2)) + "%"); } if (mainWindow != null) { mainWindow.updateStatusLabel("Removing empty mipmaps (" + phase + ") - package " + (i + 1) + " of " + list.Count + " - " + list[i].pkgPath); mainWindow.updateStatusLabel2(""); } if (ipc) { int newProgress = (list.Count * (phase - 1) + i + 1) * 100 / (list.Count * 2); if (lastProgress != newProgress) { Console.WriteLine("[IPC]TASK_PROGRESS " + newProgress); Console.Out.Flush(); lastProgress = newProgress; } } Package package = null; try { package = new Package(GameData.GamePath + list[i].pkgPath); } catch (Exception e) { if (e.Message.Contains("Problem with PCC file header:")) { return(errors); } if (ipc) { Console.WriteLine("[IPC]ERROR Issue opening package file: " + list[i].pkgPath); Console.Out.Flush(); } else { string err = ""; err += "---- Start --------------------------------------------" + Environment.NewLine; err += "Issue opening package file: " + list[i].pkgPath + Environment.NewLine; err += e.Message + Environment.NewLine + Environment.NewLine; err += e.StackTrace + Environment.NewLine + Environment.NewLine; err += "---- End ----------------------------------------------" + Environment.NewLine + Environment.NewLine; errors += err; } return(errors); } errors += removeMipMapsME1(phase, textures, package, list[i], mainWindow, installer, ipc); } return(errors); }
public void extract(string SFARfilename, string outPath) { loadHeader(SFARfilename); Directory.CreateDirectory(Path.Combine(outPath, "CookedPCConsole")); using (FileStream outputFile = new FileStream(Path.Combine(outPath, "CookedPCConsole", "Default.sfar"), FileMode.Create, FileAccess.Write)) { outputFile.WriteUInt32(SfarTag); outputFile.WriteUInt32(SfarVersion); outputFile.WriteUInt32(HeaderSize); outputFile.WriteUInt32(HeaderSize); outputFile.WriteUInt32((uint)filesList.Count); outputFile.WriteUInt32(HeaderSize); outputFile.WriteUInt32((uint)MaxBlockSize); outputFile.WriteUInt32(LZMATag); } for (int i = 0; i < filesCount; i++) { if (filenamesIndex == i) { continue; } if (filesList[i].filenamePath == null) { throw new Exception("filename missing"); } if (mainWindow != null) { mainWindow.updateStatusLabel2("File " + (i + 1) + " of " + filesList.Count() + " - " + Path.GetFileName(filesList[i].filenamePath)); } int pos = filesList[i].filenamePath.IndexOf("\\BIOGame\\DLC\\", StringComparison.OrdinalIgnoreCase); string filename = filesList[i].filenamePath.Substring(pos + ("\\BIOGame\\DLC\\").Length).Replace('/', '\\'); string dir = Path.GetDirectoryName(outPath); Directory.CreateDirectory(Path.GetDirectoryName(dir + filename)); using (FileStream outputFile = new FileStream(dir + filename, FileMode.Create, FileAccess.Write)) { sfarFile.JumpTo(filesList[i].dataOffset); if (filesList[i].compressedBlockSizesIndex == -1) { outputFile.WriteFromStream(sfarFile, filesList[i].uncomprSize); } else { List <byte[]> uncompressedBlockBuffers = new List <byte[]>(); List <byte[]> compressedBlockBuffers = new List <byte[]>(); List <long> blockBytesLeft = new List <long>(); long bytesLeft = filesList[i].uncomprSize; for (int j = 0; j < filesList[i].numBlocks; j++) { blockBytesLeft.Add(bytesLeft); int compressedBlockSize = blockSizes[filesList[i].compressedBlockSizesIndex + j]; int uncompressedBlockSize = (int)Math.Min(bytesLeft, maxBlockSize); if (compressedBlockSize == 0) { compressedBlockSize = (int)maxBlockSize; } compressedBlockBuffers.Add(sfarFile.ReadToBuffer(compressedBlockSize)); uncompressedBlockBuffers.Add(null); bytesLeft -= uncompressedBlockSize; } Parallel.For(0, filesList[i].numBlocks, j => { int compressedBlockSize = blockSizes[filesList[i].compressedBlockSizesIndex + (int)j]; int uncompressedBlockSize = (int)Math.Min(blockBytesLeft[(int)j], maxBlockSize); if (compressedBlockSize == 0 || compressedBlockSize == blockBytesLeft[(int)j]) { uncompressedBlockBuffers[(int)j] = compressedBlockBuffers[(int)j]; } else { uncompressedBlockBuffers[(int)j] = SevenZipHelper.LZMA.Decompress(compressedBlockBuffers[(int)j], (uint)uncompressedBlockSize); if (uncompressedBlockBuffers[(int)j].Length == 0) { throw new Exception(); } } }); for (int j = 0; j < filesList[i].numBlocks; j++) { outputFile.WriteFromBuffer(uncompressedBlockBuffers[j]); } } } } sfarFile.Close(); sfarFile.Dispose(); sfarFile = null; }
public string removeMipMapsME2ME3(List <FoundTexture> textures, CachePackageMgr cachePackageMgr, MainWindow mainWindow, Installer installer, bool forceZlib = false) { string errors = ""; for (int i = 0; i < GameData.packageFiles.Count; i++) { bool modified = false; if (mainWindow != null) { mainWindow.updateStatusLabel("Removing empty mipmaps - package " + (i + 1) + " of " + GameData.packageFiles.Count + " - " + GameData.packageFiles[i]); mainWindow.updateStatusLabel2(""); } if (installer != null) { installer.updateStatusMipMaps("Removing empty mipmaps " + (i * 100 / GameData.packageFiles.Count) + "%"); } Package package = null; try { if (cachePackageMgr != null) { package = cachePackageMgr.OpenPackage(GameData.packageFiles[i]); } else { package = new Package(GameData.packageFiles[i], true); } } catch (Exception e) { string err = ""; err += "---- Start --------------------------------------------" + Environment.NewLine; err += "Issue with open package file: " + GameData.packageFiles[i] + Environment.NewLine; err += e.Message + Environment.NewLine + Environment.NewLine; err += e.StackTrace + Environment.NewLine + Environment.NewLine; err += "---- End ----------------------------------------------" + Environment.NewLine + Environment.NewLine; errors += err; continue; } for (int l = 0; l < package.exportsTable.Count; l++) { int id = package.getClassNameId(package.exportsTable[l].classId); if (id == package.nameIdTexture2D || id == package.nameIdTextureFlipBook) { using (Texture texture = new Texture(package, l, package.getExportData(l), false)) { if (!texture.hasImageData() || !texture.mipMapsList.Exists(s => s.storageType == Texture.StorageTypes.empty)) { continue; } do { texture.mipMapsList.Remove(texture.mipMapsList.First(s => s.storageType == Texture.StorageTypes.empty)); } while (texture.mipMapsList.Exists(s => s.storageType == Texture.StorageTypes.empty)); texture.properties.setIntValue("SizeX", texture.mipMapsList.First().width); texture.properties.setIntValue("SizeY", texture.mipMapsList.First().height); texture.properties.setIntValue("MipTailBaseIdx", texture.mipMapsList.Count() - 1); using (MemoryStream newData = new MemoryStream()) { newData.WriteFromBuffer(texture.properties.toArray()); newData.WriteFromBuffer(texture.toArray(package.exportsTable[l].dataOffset + (uint)newData.Position)); package.setExportData(l, newData.ToArray()); } modified = true; } } } if (cachePackageMgr == null) { if (modified) { if (package.compressed && package.compressionType != Package.CompressionType.Zlib) { package.SaveToFile(forceZlib); } else { package.SaveToFile(); } } package.Dispose(); } else { package.DisposeCache(); } } if (GameData.gameType == MeType.ME3_TYPE) { TOCBinFile.UpdateAllTOCBinFiles(); } return(errors); }
public string removeMipMapsME1(int phase, List <FoundTexture> textures, CachePackageMgr cachePackageMgr, MainWindow mainWindow, Installer installer, bool forceZlib = false) { string errors = ""; for (int i = 0; i < GameData.packageFiles.Count; i++) { bool modified = false; if (mainWindow != null) { mainWindow.updateStatusLabel("Removing empty mipmaps (" + phase + ") - package " + (i + 1) + " of " + GameData.packageFiles.Count + " - " + GameData.packageFiles[i]); mainWindow.updateStatusLabel2(""); } if (installer != null) { installer.updateStatusMipMaps("Removing empty mipmaps " + ((GameData.packageFiles.Count * (phase - 1) + i + 1) * 100 / (GameData.packageFiles.Count * 2)) + "% "); } Package package = null; try { if (cachePackageMgr != null) { package = cachePackageMgr.OpenPackage(GameData.packageFiles[i]); } else { package = new Package(GameData.packageFiles[i], true); } } catch (Exception e) { string err = ""; err += "---- Start --------------------------------------------" + Environment.NewLine; err += "Issue with open package file: " + GameData.packageFiles[i] + Environment.NewLine; err += e.Message + Environment.NewLine + Environment.NewLine; err += e.StackTrace + Environment.NewLine + Environment.NewLine; err += "---- End ----------------------------------------------" + Environment.NewLine + Environment.NewLine; errors += err; continue; } for (int l = 0; l < package.exportsTable.Count; l++) { int id = package.getClassNameId(package.exportsTable[l].classId); if (id == package.nameIdTexture2D || id == package.nameIdTextureFlipBook) { using (Texture texture = new Texture(package, l, package.getExportData(l), false)) { if (!texture.hasImageData() || !texture.mipMapsList.Exists(s => s.storageType == Texture.StorageTypes.empty)) { continue; } do { texture.mipMapsList.Remove(texture.mipMapsList.First(s => s.storageType == Texture.StorageTypes.empty)); } while (texture.mipMapsList.Exists(s => s.storageType == Texture.StorageTypes.empty)); texture.properties.setIntValue("SizeX", texture.mipMapsList.First().width); texture.properties.setIntValue("SizeY", texture.mipMapsList.First().height); texture.properties.setIntValue("MipTailBaseIdx", texture.mipMapsList.Count() - 1); FoundTexture foundTexture = new FoundTexture(); int foundListEntry = -1; string pkgName = GameData.RelativeGameData(package.packagePath).ToLowerInvariant(); for (int k = 0; k < textures.Count; k++) { for (int t = 0; t < textures[k].list.Count; t++) { if (textures[k].list[t].exportID == l && textures[k].list[t].path.ToLowerInvariant() == pkgName) { foundTexture = textures[k]; foundListEntry = t; break; } } } if (foundListEntry == -1) { errors += "Error: Texture " + package.exportsTable[l].objectName + " not found in package: " + GameData.packageFiles[i] + ", skipping..." + Environment.NewLine; goto skip; } if (foundTexture.list[foundListEntry].linkToMaster != -1) { if (phase == 1) { continue; } MatchedTexture foundMasterTex = foundTexture.list[foundTexture.list[foundListEntry].linkToMaster]; Package masterPkg = null; if (cachePackageMgr != null) { masterPkg = cachePackageMgr.OpenPackage(GameData.GamePath + foundMasterTex.path); } else { masterPkg = new Package(GameData.GamePath + foundMasterTex.path); } int masterExportId = foundMasterTex.exportID; byte[] masterData = masterPkg.getExportData(masterExportId); masterPkg.DisposeCache(); using (Texture masterTexture = new Texture(masterPkg, masterExportId, masterData, false)) { if (texture.mipMapsList.Count != masterTexture.mipMapsList.Count) { errors += "Error: Texture " + package.exportsTable[l].objectName + " in package: " + GameData.packageFiles[i] + " has wrong reference, skipping..." + Environment.NewLine; goto skip; } for (int t = 0; t < texture.mipMapsList.Count; t++) { Texture.MipMap mipmap = texture.mipMapsList[t]; if (mipmap.storageType == Texture.StorageTypes.extLZO || mipmap.storageType == Texture.StorageTypes.extZlib || mipmap.storageType == Texture.StorageTypes.extUnc) { mipmap.dataOffset = masterPkg.exportsTable[masterExportId].dataOffset + (uint)masterTexture.properties.propertyEndOffset + masterTexture.mipMapsList[t].internalOffset; texture.mipMapsList[t] = mipmap; } } } if (cachePackageMgr == null) { masterPkg.Dispose(); } } skip: using (MemoryStream newData = new MemoryStream()) { newData.WriteFromBuffer(texture.properties.toArray()); newData.WriteFromBuffer(texture.toArray(package.exportsTable[l].dataOffset + (uint)newData.Position)); package.setExportData(l, newData.ToArray()); } modified = true; } } } if (cachePackageMgr == null) { if (modified) { if (package.compressed && package.compressionType != Package.CompressionType.Zlib) { package.SaveToFile(forceZlib); } else { package.SaveToFile(); } } package.Dispose(); } else { package.DisposeCache(); } } return(errors); }
private bool generateBuiltinMapFiles = false; // change to true to enable map files generation public string PrepareListOfTextures(TexExplorer texEplorer, CachePackageMgr cachePackageMgr, MainWindow mainWindow, Installer installer, ref string log, bool force = false) { string errors = ""; treeScan = null; List <FoundTexture> textures = new List <FoundTexture>(); string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), Assembly.GetExecutingAssembly().GetName().Name); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } string filename = Path.Combine(path, "me" + (int)GameData.gameType + "map.bin"); if (force && File.Exists(filename)) { File.Delete(filename); } if (File.Exists(filename)) { using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.ReadWrite)) { uint tag = fs.ReadUInt32(); uint version = fs.ReadUInt32(); if (tag != TexExplorer.textureMapBinTag || version != TexExplorer.textureMapBinVersion) { if (mainWindow != null) { MessageBox.Show("Detected wrong or old version of textures scan file!" + "\n\nYou need to restore the game to vanilla state then reinstall optional DLC/PCC mods." + "\n\nThen from the main menu, select 'Remove Textures Scan File' and start Texture Manager again."); mainWindow.updateStatusLabel(""); mainWindow.updateStatusLabel2(""); texEplorer.Close(); } fs.Close(); log += "Detected wrong or old version of textures scan file!" + Environment.NewLine; log += "You need to restore the game to vanilla state then reinstall optional DLC/PCC mods." + Environment.NewLine; log += "Then from the main menu, select 'Remove Textures Scan File' and start Texture Manager again." + Environment.NewLine; return("Detected wrong or old version of textures scan file!" + Environment.NewLine + "You need to restore the game to vanilla state then reinstall optional DLC/PCC mods." + Environment.NewLine + "Then from the main menu, select 'Remove Textures Scan File' and start Texture Manager again." + Environment.NewLine); } uint countTexture = fs.ReadUInt32(); for (int i = 0; i < countTexture; i++) { FoundTexture texture = new FoundTexture(); int len = fs.ReadInt32(); texture.name = fs.ReadStringASCII(len); texture.crc = fs.ReadUInt32(); uint countPackages = fs.ReadUInt32(); texture.list = new List <MatchedTexture>(); for (int k = 0; k < countPackages; k++) { MatchedTexture matched = new MatchedTexture(); matched.exportID = fs.ReadInt32(); matched.linkToMaster = fs.ReadInt32(); len = fs.ReadInt32(); matched.path = fs.ReadStringASCII(len); texture.list.Add(matched); } textures.Add(texture); } List <string> packages = new List <string>(); int numPackages = fs.ReadInt32(); for (int i = 0; i < numPackages; i++) { int len = fs.ReadInt32(); string pkgPath = fs.ReadStringASCII(len); pkgPath = GameData.GamePath + pkgPath; packages.Add(pkgPath); } for (int i = 0; i < packages.Count; i++) { if (GameData.packageFiles.Find(s => s.Equals(packages[i], StringComparison.OrdinalIgnoreCase)) == null) { if (mainWindow != null) { MessageBox.Show("Detected removal of game files since last game data scan." + "\n\nYou need to restore the game to vanilla state then reinstall optional DLC/PCC mods." + "\n\nThen from the main menu, select 'Remove Textures Scan File' and start Texture Manager again."); return(""); } else if (!force) { errors += "Detected removal of game files since last game data scan." + Environment.NewLine + Environment.NewLine + "You need to restore the game to vanilla state then reinstall optional DLC/PCC mods."; return(""); } } } for (int i = 0; i < GameData.packageFiles.Count; i++) { if (packages.Find(s => s.Equals(GameData.packageFiles[i], StringComparison.OrdinalIgnoreCase)) == null) { if (mainWindow != null) { MessageBox.Show("Detected additional game files not present in latest game data scan." + "\n\nYou need to restore the game to vanilla state then reinstall optional DLC/PCC mods." + "\n\nThen from the main menu, select 'Remove Textures Scan File' and start Texture Manager again."); return(""); } else if (!force) { errors += "Detected additional game files not present in latest game data scan." + Environment.NewLine + Environment.NewLine + "You need to restore the game to vanilla state then reinstall optional DLC/PCC mods."; return(""); } } } treeScan = textures; if (mainWindow != null) { mainWindow.updateStatusLabel(""); mainWindow.updateStatusLabel2(""); } return(errors); } } if (File.Exists(filename)) { File.Delete(filename); } if (mainWindow != null) { List <string> badMods = Misc.detectBrokenMod(GameData.gameType); if (badMods.Count != 0) { errors = ""; for (int l = 0; l < badMods.Count; l++) { errors += badMods[l] + Environment.NewLine; } MessageBox.Show("Detected not compatible mods: \n\n" + errors); return(""); } } if (MipMaps.checkGameDataModded(cachePackageMgr)) { if (mainWindow != null) { MessageBox.Show("Detected modded game. Can not continue." + "\n\nYou need to restore the game to vanilla state then reinstall optional DLC/PCC mods." + "\n\nThen start Texture Manager again."); return(""); } else if (!force) { errors += "Detected modded game. Can not continue." + Environment.NewLine + Environment.NewLine + "You need to restore the game to vanilla state then reinstall optional DLC/PCC mods."; return(""); } } if (mainWindow != null) { DialogResult result = MessageBox.Show("Replacing textures and creating mods requires generating a map of the game's textures.\n" + "You only need to do it once.\n\n" + "IMPORTANT! Your game needs to be in vanilla state and have optional DLC/PCC mods installed.\n\n" + "Are you sure you want to proceed?", "Textures mapping", MessageBoxButtons.YesNo); if (result == DialogResult.No) { texEplorer.Close(); return(""); } } GameData.packageFiles.Sort(); if (mainWindow != null) { Misc.startTimer(); } for (int i = 0; i < GameData.packageFiles.Count; i++) { if (mainWindow != null) { mainWindow.updateStatusLabel("Finding textures in package " + (i + 1) + " of " + GameData.packageFiles.Count + " - " + GameData.packageFiles[i]); } if (installer != null) { installer.updateStatusScan("Scanning textures " + (i * 100 / GameData.packageFiles.Count) + "% "); } errors += FindTextures(textures, GameData.packageFiles[i], cachePackageMgr, ref log); } if (GameData.gameType == MeType.ME1_TYPE) { for (int k = 0; k < textures.Count; k++) { for (int t = 0; t < textures[k].list.Count; t++) { uint mipmapOffset = textures[k].list[t].mipmapOffset; if (textures[k].list[t].slave) { MatchedTexture slaveTexture = textures[k].list[t]; string basePkgName = slaveTexture.basePackageName; if (basePkgName == Path.GetFileNameWithoutExtension(slaveTexture.path).ToUpperInvariant()) { throw new Exception(); } bool found = false; for (int j = 0; j < textures[k].list.Count; j++) { if (!textures[k].list[j].slave && textures[k].list[j].mipmapOffset == mipmapOffset && textures[k].list[j].packageName == basePkgName) { slaveTexture.linkToMaster = j; textures[k].list[t] = slaveTexture; found = true; break; } } if (!found) { log += "Error: not able match 'slave' texture: + " + textures[k].name + " to 'master'."; } } } if (!textures[k].list.Exists(s => s.slave) && textures[k].list.Exists(s => s.weakSlave)) { List <MatchedTexture> texList = new List <MatchedTexture>(); for (int t = 0; t < textures[k].list.Count; t++) { MatchedTexture tex = textures[k].list[t]; if (tex.weakSlave) { texList.Add(tex); } else { texList.Insert(0, tex); } } FoundTexture f = textures[k]; f.list = texList; textures[k] = f; if (textures[k].list[0].weakSlave) { continue; } for (int t = 0; t < textures[k].list.Count; t++) { if (textures[k].list[t].weakSlave) { MatchedTexture slaveTexture = textures[k].list[t]; string basePkgName = slaveTexture.basePackageName; if (basePkgName == Path.GetFileNameWithoutExtension(slaveTexture.path).ToUpperInvariant()) { throw new Exception(); } for (int j = 0; j < textures[k].list.Count; j++) { if (!textures[k].list[j].weakSlave && textures[k].list[j].packageName == basePkgName) { slaveTexture.linkToMaster = j; textures[k].list[t] = slaveTexture; break; } } } } } } } using (FileStream fs = new FileStream(filename, FileMode.Create, FileAccess.Write)) { MemoryStream mem = new MemoryStream(); mem.WriteUInt32(TexExplorer.textureMapBinTag); mem.WriteUInt32(TexExplorer.textureMapBinVersion); mem.WriteInt32(textures.Count); for (int i = 0; i < textures.Count; i++) { mem.WriteInt32(textures[i].name.Length); mem.WriteStringASCII(textures[i].name); mem.WriteUInt32(textures[i].crc); if (generateBuiltinMapFiles) { mem.WriteInt32(textures[i].width); mem.WriteInt32(textures[i].height); mem.WriteInt32((int)textures[i].pixfmt); mem.WriteInt32(textures[i].alphadxt1 ? 1 : 0); mem.WriteInt32(textures[i].numMips); } mem.WriteInt32(textures[i].list.Count); for (int k = 0; k < textures[i].list.Count; k++) { mem.WriteInt32(textures[i].list[k].exportID); mem.WriteInt32(textures[i].list[k].linkToMaster); mem.WriteInt32(textures[i].list[k].path.Length); mem.WriteStringASCII(textures[i].list[k].path); } } if (!generateBuiltinMapFiles) { mem.WriteInt32(GameData.packageFiles.Count); for (int i = 0; i < GameData.packageFiles.Count; i++) { string s = GameData.RelativeGameData(GameData.packageFiles[i]); mem.WriteInt32(s.Length); mem.WriteStringASCII(s); } } mem.SeekBegin(); if (generateBuiltinMapFiles) { fs.WriteUInt32(0x504D5443); fs.WriteUInt32((uint)mem.Length); byte[] compressed = new ZlibHelper.Zlib().Compress(mem.ToArray(), 9); fs.WriteUInt32((uint)compressed.Length); fs.WriteFromBuffer(compressed); } else { fs.WriteFromStream(mem, mem.Length); } } if (mainWindow != null) { if (!generateBuiltinMapFiles) { MipMaps mipmaps = new MipMaps(); if (GameData.gameType == MeType.ME1_TYPE) { errors += mipmaps.removeMipMapsME1(1, textures, null, mainWindow, null); errors += mipmaps.removeMipMapsME1(2, textures, null, mainWindow, null); } else { errors += mipmaps.removeMipMapsME2ME3(textures, null, mainWindow, null); } } var time = Misc.stopTimer(); mainWindow.updateStatusLabel("Done. Process total time: " + Misc.getTimerFormat(time)); mainWindow.updateStatusLabel2(""); } treeScan = textures; return(errors); }
public void RepackTexturesTFC(List <FoundTexture> textures, MainWindow mainWindow, CachePackageMgr cachePackageMgr) { if (GameData.gameType == MeType.ME2_TYPE) { for (int i = 0; i < textures.Count; i++) { FoundTexture foundTexture = textures[i]; if (mainWindow != null) { mainWindow.updateStatusLabel("Texture: " + (i + 1) + " of " + textures.Count); mainWindow.updateStatusLabel2(""); } string TFCfilename = "", TFCfilenameTemp, prevTFCfilename = ""; Texture prevTexture = null; for (int index2 = 0; index2 < foundTexture.list.Count; index2++) { MatchedTexture matchedTexture = foundTexture.list[index2]; string packagePath = GameData.GamePath + matchedTexture.path; Package package = cachePackageMgr.OpenPackage(packagePath); Texture texture = new Texture(package, matchedTexture.exportID, package.getExportData(matchedTexture.exportID)); if (!texture.mipMapsList.Exists(b => b.storageType == Texture.StorageTypes.extLZO || b.storageType == Texture.StorageTypes.extUnc || b.storageType == Texture.StorageTypes.extZlib)) { continue; } bool modified = false; for (int l = 0; l < texture.mipMapsList.Count; l++) { Texture.MipMap mipmap = texture.mipMapsList[l]; if (((int)mipmap.storageType & (int)Texture.StorageFlags.externalFile) != 0) { string archive = texture.properties.getProperty("TextureFileCacheName").valueName; TFCfilename = Path.Combine(GameData.MainData, archive + ".tfc"); if (packagePath.ToLowerInvariant().Contains("\\dlc")) { string DLCArchiveFile = Path.Combine(Path.GetDirectoryName(packagePath), archive + ".tfc"); if (File.Exists(DLCArchiveFile)) { TFCfilename = DLCArchiveFile; } else if (GameData.gameType == MeType.ME2_TYPE) { TFCfilename = Path.Combine(GameData.MainData, "Textures.tfc"); } } TFCfilenameTemp = TFCfilename + ".TempTFC"; if (!File.Exists(TFCfilenameTemp)) { using (FileStream fs = new FileStream(TFCfilenameTemp, FileMode.CreateNew, FileAccess.Write)) { byte[] guid = new byte[16]; Array.Copy(texture.properties.getProperty("TFCFileGuid").valueStruct, guid, 16); fs.WriteFromBuffer(guid); } } if (TFCfilename != prevTFCfilename) { using (FileStream fs = new FileStream(TFCfilename, FileMode.Open, FileAccess.Read)) { fs.JumpTo(mipmap.dataOffset); using (FileStream fsNew = new FileStream(TFCfilenameTemp, FileMode.Append, FileAccess.Write)) { fsNew.SeekEnd(); mipmap.dataOffset = (uint)fsNew.Position; if (mipmap.storageType == Texture.StorageTypes.extLZO || mipmap.storageType == Texture.StorageTypes.extZlib) { fsNew.WriteFromStream(fs, mipmap.compressedSize); } else { fsNew.WriteFromStream(fs, mipmap.uncompressedSize); } } } } else { Texture.MipMap tmpMipmap = prevTexture.getMipmap(mipmap.width, mipmap.height); if (mipmap.storageType != tmpMipmap.storageType) { throw new Exception(""); } mipmap.dataOffset = tmpMipmap.dataOffset; } texture.mipMapsList[l] = mipmap; modified = true; } } if (modified) { prevTFCfilename = TFCfilename; prevTexture = texture; using (MemoryStream newData = new MemoryStream()) { newData.WriteFromBuffer(texture.properties.toArray()); newData.WriteFromBuffer(texture.toArray(package.exportsTable[matchedTexture.exportID].dataOffset + (uint)newData.Position)); //package.setExportData(matchedTexture.exportID, newData.ToArray()); } } } } } if (mainWindow != null) { mainWindow.updateStatusLabel(""); } List <string> tfcFles = Directory.GetFiles(GameData.GamePath, "*.TempTFC", SearchOption.AllDirectories).Where(item => item.EndsWith(".TempTFC", StringComparison.OrdinalIgnoreCase)).ToList(); for (int i = 0; i < tfcFles.Count; i++) { string newname = tfcFles[i].Substring(0, tfcFles[i].IndexOf(".TempTFC")); File.Delete(newname); File.Move(tfcFles[i], newname); } //cachePackageMgr.CloseAllWithSave(); if (mainWindow != null) { mainWindow.updateStatusLabel("Done."); mainWindow.updateStatusLabel(""); } }
public string PrepareListOfTextures(MeType gameId, TexExplorer texEplorer, MainWindow mainWindow, Installer installer, ref string log, bool ipc) { string errors = ""; treeScan = null; Misc.MD5FileEntry[] md5Entries; if (gameId == MeType.ME1_TYPE) { pkgs = Program.tablePkgsME1; md5Entries = Program.entriesME1; } else if (gameId == MeType.ME2_TYPE) { pkgs = Program.tablePkgsME2; md5Entries = Program.entriesME2; } else { pkgs = Program.tablePkgsME3; md5Entries = Program.entriesME3; } List <FoundTexture> textures = new List <FoundTexture>(); string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), Assembly.GetExecutingAssembly().GetName().Name); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } string filename = Path.Combine(path, "me" + (int)gameId + "map.bin"); if (mainWindow != null) { if (File.Exists(filename)) { using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.ReadWrite)) { uint tag = fs.ReadUInt32(); uint version = fs.ReadUInt32(); if (tag != textureMapBinTag || version != textureMapBinVersion) { MessageBox.Show("Detected wrong or old version of textures scan file!" + "\n\nYou need to restore the game to vanilla state then reinstall optional DLC/PCC mods." + "\n\nThen from the main menu, select 'Remove Textures Scan File' and start Texture Manager again."); mainWindow.updateStatusLabel(""); mainWindow.updateStatusLabel2(""); texEplorer.Close(); fs.Close(); log += "Detected wrong or old version of textures scan file!" + Environment.NewLine; log += "You need to restore the game to vanilla state then reinstall optional DLC/PCC mods." + Environment.NewLine; log += "Then from the main menu, select 'Remove Textures Scan File' and start Texture Manager again." + Environment.NewLine; return("Detected wrong or old version of textures scan file!" + Environment.NewLine + "You need to restore the game to vanilla state then reinstall optional DLC/PCC mods." + Environment.NewLine + "Then from the main menu, select 'Remove Textures Scan File' and start Texture Manager again." + Environment.NewLine); } uint countTexture = fs.ReadUInt32(); for (int i = 0; i < countTexture; i++) { FoundTexture texture = new FoundTexture(); int len = fs.ReadInt32(); texture.name = fs.ReadStringASCII(len); texture.crc = fs.ReadUInt32(); uint countPackages = fs.ReadUInt32(); texture.list = new List <MatchedTexture>(); for (int k = 0; k < countPackages; k++) { MatchedTexture matched = new MatchedTexture(); matched.exportID = fs.ReadInt32(); matched.linkToMaster = fs.ReadInt32(); len = fs.ReadInt32(); matched.path = fs.ReadStringASCII(len); texture.list.Add(matched); } textures.Add(texture); } List <string> packages = new List <string>(); int numPackages = fs.ReadInt32(); for (int i = 0; i < numPackages; i++) { int len = fs.ReadInt32(); string pkgPath = fs.ReadStringASCII(len); pkgPath = GameData.GamePath + pkgPath; packages.Add(pkgPath); } for (int i = 0; i < packages.Count; i++) { if (GameData.packageFiles.Find(s => s.Equals(packages[i], StringComparison.OrdinalIgnoreCase)) == null) { MessageBox.Show("Detected removal of game files since last game data scan." + "\n\nYou need to restore the game to vanilla state then reinstall optional DLC/PCC mods." + "\n\nThen from the main menu, select 'Remove Textures Scan File' and start Texture Manager again."); return(""); } } for (int i = 0; i < GameData.packageFiles.Count; i++) { if (packages.Find(s => s.Equals(GameData.packageFiles[i], StringComparison.OrdinalIgnoreCase)) == null) { MessageBox.Show("Detected additional game files not present in latest game data scan." + "\n\nYou need to restore the game to vanilla state then reinstall optional DLC/PCC mods." + "\n\nThen from the main menu, select 'Remove Textures Scan File' and start Texture Manager again."); return(""); } } treeScan = textures; mainWindow.updateStatusLabel(""); mainWindow.updateStatusLabel2(""); } if (!texEplorer.verifyGameDataEmptyMipMapsRemoval()) { MessageBox.Show("Detected empty mips in game files." + "\n\nYou need the game in vanilla state and optional DLC/PCC mods." + "\n\nThen from the main menu, select 'Remove Textures Scan File' and start Texture Manager again."); return(""); } return(errors); } if (mainWindow != null) { List <string> badMods = Misc.detectBrokenMod(GameData.gameType); if (badMods.Count != 0) { errors = ""; for (int l = 0; l < badMods.Count; l++) { errors += badMods[l] + Environment.NewLine; } MessageBox.Show("Detected not compatible mods: \n\n" + errors); return(""); } List <string> mods = Misc.detectMods(GameData.gameType); if (mods.Count != 0 && GameData.gameType == MeType.ME1_TYPE && GameData.FullScanME1Game) { errors = ""; for (int l = 0; l < mods.Count; l++) { errors += mods[l] + Environment.NewLine; } DialogResult resp = MessageBox.Show("Detected NOT compatible/supported mods with this version of game: \n\n" + errors + "\n\nPress Cancel to abort or press Ok button to continue.", "Warning !", MessageBoxButtons.OKCancel); if (resp == DialogResult.Cancel) { return(""); } } } DialogResult result = MessageBox.Show("Replacing textures and creating mods requires generating a map of the game's textures.\n" + "You only need to do it once.\n\n" + "IMPORTANT! Your game needs to be in vanilla state and have optional DLC/PCC mods installed.\n\n" + "Are you sure you want to proceed?", "Textures mapping", MessageBoxButtons.YesNo); if (result == DialogResult.No) { texEplorer.Close(); return(""); } Misc.startTimer(); } if (!GameData.FullScanME1Game) { int count = GameData.packageFiles.Count; for (int i = 0; i < count; i++) { if (GameData.packageFiles[i].Contains("_IT.") || GameData.packageFiles[i].Contains("_FR.") || GameData.packageFiles[i].Contains("_ES.") || GameData.packageFiles[i].Contains("_DE.") || GameData.packageFiles[i].Contains("_RA.") || GameData.packageFiles[i].Contains("_RU.") || GameData.packageFiles[i].Contains("_PLPC.") || GameData.packageFiles[i].Contains("_DEU.") || GameData.packageFiles[i].Contains("_FRA.") || GameData.packageFiles[i].Contains("_ITA.") || GameData.packageFiles[i].Contains("_POL.")) { GameData.packageFiles.Add(GameData.packageFiles[i]); GameData.packageFiles.RemoveAt(i--); count--; } } } if (!generateBuiltinMapFiles && !GameData.FullScanME1Game) { List <string> addedFiles = new List <string>(); List <string> modifiedFiles = new List <string>(); loadTexturesMap(gameId, textures); List <string> sortedFiles = new List <string>(); for (int i = 0; i < GameData.packageFiles.Count; i++) { sortedFiles.Add(GameData.RelativeGameData(GameData.packageFiles[i]).ToLowerInvariant()); } sortedFiles.Sort(); for (int k = 0; k < textures.Count; k++) { for (int t = 0; t < textures[k].list.Count; t++) { string pkgPath = textures[k].list[t].path.ToLowerInvariant(); if (sortedFiles.BinarySearch(pkgPath) >= 0) { continue; } MatchedTexture f = textures[k].list[t]; f.path = ""; textures[k].list[t] = f; } } if (installer != null) { installer.updateProgressStatus("Scanning packages"); } if (mainWindow != null) { mainWindow.updateStatusLabel("Scanning packages..."); } if (ipc) { Console.WriteLine("[IPC]STAGE_CONTEXT STAGE_SCAN"); Console.Out.Flush(); } for (int i = 0; i < GameData.packageFiles.Count; i++) { int index = -1; bool modified = true; bool foundPkg = false; string package = GameData.RelativeGameData(GameData.packageFiles[i].ToLowerInvariant()); long packageSize = new FileInfo(GameData.packageFiles[i]).Length; for (int p = 0; p < md5Entries.Length; p++) { if (package == md5Entries[p].path.ToLowerInvariant()) { foundPkg = true; if (packageSize == md5Entries[p].size) { modified = false; break; } index = p; } } if (foundPkg && modified) { modifiedFiles.Add(md5Entries[index].path); } else if (!foundPkg) { addedFiles.Add(GameData.RelativeGameData(GameData.packageFiles[i])); } } int lastProgress = -1; int totalPackages = modifiedFiles.Count + addedFiles.Count; int currentPackage = 0; if (ipc) { Console.WriteLine("[IPC]STAGE_WEIGHT STAGE_SCAN " + string.Format("{0:0.000000}", ((float)totalPackages / GameData.packageFiles.Count))); Console.Out.Flush(); } for (int i = 0; i < modifiedFiles.Count; i++, currentPackage++) { if (installer != null) { installer.updateProgressStatus("Scanning textures " + ((currentPackage + 1) * 100) / totalPackages + "% "); } if (mainWindow != null) { mainWindow.updateStatusLabel("Finding textures in package " + (currentPackage + 1) + " of " + totalPackages + " - " + modifiedFiles[i]); } if (ipc) { Console.WriteLine("[IPC]PROCESSING_FILE " + modifiedFiles[i]); int newProgress = currentPackage * 100 / totalPackages; if (lastProgress != newProgress) { Console.WriteLine("[IPC]TASK_PROGRESS " + newProgress); lastProgress = newProgress; } Console.Out.Flush(); } errors += FindTextures(gameId, textures, modifiedFiles[i], true, ref log); } for (int i = 0; i < addedFiles.Count; i++, currentPackage++) { if (installer != null) { installer.updateProgressStatus("Scanning textures " + ((currentPackage + 1) * 100) / totalPackages + "% "); } if (mainWindow != null) { mainWindow.updateStatusLabel("Finding textures in package " + (currentPackage + 1) + " of " + totalPackages + " - " + addedFiles[i]); } if (ipc) { Console.WriteLine("[IPC]PROCESSING_FILE " + addedFiles[i]); int newProgress = currentPackage * 100 / totalPackages; if (lastProgress != newProgress) { Console.WriteLine("[IPC]TASK_PROGRESS " + newProgress); lastProgress = newProgress; } Console.Out.Flush(); } errors += FindTextures(gameId, textures, addedFiles[i], false, ref log); } for (int k = 0; k < textures.Count; k++) { bool found = false; for (int t = 0; t < textures[k].list.Count; t++) { if (textures[k].list[t].path != "") { found = true; break; } } if (!found) { textures[k].list.Clear(); textures.Remove(textures[k]); k--; } } } else { int lastProgress = -1; for (int i = 0; i < GameData.packageFiles.Count; i++) { if (installer != null) { installer.updateProgressStatus("Scanning textures " + ((i + 1) * 100) / GameData.packageFiles.Count + "% "); } if (mainWindow != null) { mainWindow.updateStatusLabel("Finding textures in package " + (i + 1) + " of " + GameData.packageFiles.Count + " - " + GameData.packageFiles[i]); } if (ipc) { Console.WriteLine("[IPC]PROCESSING_FILE " + GameData.packageFiles[i]); int newProgress = i * 100 / GameData.packageFiles.Count; if (lastProgress != newProgress) { Console.WriteLine("[IPC]TASK_PROGRESS " + newProgress); lastProgress = newProgress; } Console.Out.Flush(); } FindTextures(gameId, textures, GameData.RelativeGameData(GameData.packageFiles[i]), false, ref log); } } if (gameId == MeType.ME1_TYPE) { for (int k = 0; k < textures.Count; k++) { for (int t = 0; t < textures[k].list.Count; t++) { uint mipmapOffset = textures[k].list[t].mipmapOffset; if (textures[k].list[t].slave) { MatchedTexture slaveTexture = textures[k].list[t]; string basePkgName = slaveTexture.basePackageName; if (basePkgName == Path.GetFileNameWithoutExtension(slaveTexture.path).ToUpperInvariant()) { throw new Exception(); } for (int j = 0; j < textures[k].list.Count; j++) { if (!textures[k].list[j].slave && textures[k].list[j].mipmapOffset == mipmapOffset && textures[k].list[j].packageName == basePkgName) { slaveTexture.linkToMaster = j; slaveTexture.slave = true; textures[k].list[t] = slaveTexture; break; } } } } if (!textures[k].list.Exists(s => s.slave) && textures[k].list.Exists(s => s.weakSlave)) { List <MatchedTexture> texList = new List <MatchedTexture>(); for (int t = 0; t < textures[k].list.Count; t++) { MatchedTexture tex = textures[k].list[t]; if (tex.weakSlave) { texList.Add(tex); } else { texList.Insert(0, tex); } } FoundTexture f = textures[k]; f.list = texList; textures[k] = f; if (textures[k].list[0].weakSlave) { continue; } for (int t = 0; t < textures[k].list.Count; t++) { if (textures[k].list[t].weakSlave) { MatchedTexture slaveTexture = textures[k].list[t]; string basePkgName = slaveTexture.basePackageName; if (basePkgName == Path.GetFileNameWithoutExtension(slaveTexture.path).ToUpperInvariant()) { throw new Exception(); } for (int j = 0; j < textures[k].list.Count; j++) { if (!textures[k].list[j].weakSlave && textures[k].list[j].packageName == basePkgName) { slaveTexture.linkToMaster = j; slaveTexture.slave = true; textures[k].list[t] = slaveTexture; break; } } } } } } } if (File.Exists(filename)) { File.Delete(filename); } using (FileStream fs = new FileStream(filename, FileMode.Create, FileAccess.Write)) { MemoryStream mem = new MemoryStream(); mem.WriteUInt32(textureMapBinTag); mem.WriteUInt32(textureMapBinVersion); mem.WriteInt32(textures.Count); for (int i = 0; i < textures.Count; i++) { if (generateBuiltinMapFiles) { mem.WriteByte((byte)textures[i].name.Length); } else { mem.WriteInt32(textures[i].name.Length); } mem.WriteStringASCII(textures[i].name); mem.WriteUInt32(textures[i].crc); if (generateBuiltinMapFiles) { mem.WriteInt16((short)textures[i].width); mem.WriteInt16((short)textures[i].height); mem.WriteByte((byte)textures[i].pixfmt); mem.WriteByte((byte)textures[i].flags); mem.WriteInt16((short)textures[i].list.Count); } else { mem.WriteInt32(textures[i].list.Count); } for (int k = 0; k < textures[i].list.Count; k++) { mem.WriteInt32(textures[i].list[k].exportID); if (generateBuiltinMapFiles) { if (GameData.gameType == MeType.ME1_TYPE) { mem.WriteInt16((short)textures[i].list[k].linkToMaster); if (textures[i].list[k].linkToMaster != -1) { mem.WriteStringASCIINull(textures[i].list[k].basePackageName); } } mem.WriteByte(textures[i].list[k].removeEmptyMips ? (byte)1 : (byte)0); mem.WriteByte((byte)textures[i].list[k].numMips); mem.WriteInt16((short)pkgs.IndexOf(textures[i].list[k].path)); } else { mem.WriteInt32(textures[i].list[k].linkToMaster); mem.WriteInt32(textures[i].list[k].path.Length); mem.WriteStringASCII(textures[i].list[k].path); } } } if (!generateBuiltinMapFiles) { mem.WriteInt32(GameData.packageFiles.Count); for (int i = 0; i < GameData.packageFiles.Count; i++) { string s = GameData.RelativeGameData(GameData.packageFiles[i]); mem.WriteInt32(s.Length); mem.WriteStringASCII(s); } } mem.SeekBegin(); if (generateBuiltinMapFiles) { fs.WriteUInt32(0x504D5443); fs.WriteUInt32((uint)mem.Length); byte[] compressed = new ZlibHelper.Zlib().Compress(mem.ToArray(), 9); fs.WriteUInt32((uint)compressed.Length); fs.WriteFromBuffer(compressed); } else { fs.WriteFromStream(mem, mem.Length); } } if (mainWindow != null) { if (!generateBuiltinMapFiles) { MipMaps mipmaps = new MipMaps(); if (GameData.gameType == MeType.ME1_TYPE) { errors += mipmaps.removeMipMapsME1(1, textures, mainWindow, null, false); errors += mipmaps.removeMipMapsME1(2, textures, mainWindow, null, false); } else { errors += mipmaps.removeMipMapsME2ME3(textures, mainWindow, null, false, false); } if (GameData.gameType == MeType.ME3_TYPE) { TOCBinFile.UpdateAllTOCBinFiles(); } } } treeScan = textures; if (mainWindow != null) { var time = Misc.stopTimer(); mainWindow.updateStatusLabel("Done. Process total time: " + Misc.getTimerFormat(time)); mainWindow.updateStatusLabel2(""); } return(errors); }
public string createTextureMod(string inDir, string outFile, List <FoundTexture> textures, MainWindow mainWindow, ref string log) { string errors = ""; int count = 0; List <string> files = Directory.GetFiles(inDir, "*.dds").Where(item => item.EndsWith(".dds", StringComparison.OrdinalIgnoreCase)).ToList(); files.Sort(); List <FileMod> modFiles = new List <FileMod>(); using (FileStream outFs = new FileStream(outFile, FileMode.Create, FileAccess.Write)) { outFs.WriteUInt32(TexExplorer.TextureModTag); outFs.WriteUInt32(TexExplorer.TextureModVersion); outFs.WriteInt64(0); // files info offset - filled later for (int n = 0; n < files.Count(); n++) { string file = files[n]; if (mainWindow != null) { mainWindow.updateStatusLabel("Creating MOD: " + Path.GetFileName(outFile)); mainWindow.updateStatusLabel2("Texture " + (n + 1) + " of " + files.Count() + ", File: " + Path.GetFileName(file)); } string filename = Path.GetFileNameWithoutExtension(file).ToLowerInvariant(); if (!filename.Contains("0x")) { errors += "Texture filename not valid: " + Path.GetFileName(file) + " Texture filename must include texture CRC (0xhhhhhhhh). Skipping texture..." + Environment.NewLine; log += "Texture filename not valid: " + Path.GetFileName(file) + " Texture filename must include texture CRC (0xhhhhhhhh). Skipping texture..." + Environment.NewLine; continue; } int idx = filename.IndexOf("0x"); if (filename.Length - idx < 10) { errors += "Texture filename not valid: " + Path.GetFileName(file) + " Texture filename must include texture CRC (0xhhhhhhhh). Skipping texture..." + Environment.NewLine; log += "Texture filename not valid: " + Path.GetFileName(file) + " Texture filename must include texture CRC (0xhhhhhhhh). Skipping texture..." + Environment.NewLine; continue; } uint crc; string crcStr = filename.Substring(idx + 2, 8); try { crc = uint.Parse(crcStr, System.Globalization.NumberStyles.HexNumber); } catch { errors += "Texture filename not valid: " + Path.GetFileName(file) + " Texture filename must include texture CRC (_0xhhhhhhhh). Skipping texture..." + Environment.NewLine; log += "Texture filename not valid: " + Path.GetFileName(file) + " Texture filename must include texture CRC (_0xhhhhhhhh). Skipping texture..." + Environment.NewLine; continue; } List <FoundTexture> foundCrcList = textures.FindAll(s => s.crc == crc); if (foundCrcList.Count == 0) { errors += "Texture skipped. Texture " + Path.GetFileName(file) + " is not present in your game setup." + Environment.NewLine; log += "Texture skipped. Texture " + Path.GetFileName(file) + " is not present in your game setup." + Environment.NewLine; continue; } int savedCount = count; using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read)) { byte[] src = fs.ReadToBuffer((int)fs.Length); DDSImage image = new DDSImage(new MemoryStream(src)); if (!image.checkExistAllMipmaps()) { errors += "Error in texture: " + Path.GetFileName(file) + " This texture has not all the required mipmaps, skipping texture..." + Environment.NewLine; log += "Error in texture: " + Path.GetFileName(file) + " This texture has not all the required mipmaps, skipping texture..." + Environment.NewLine; continue; } Package pkg = new Package(GameData.GamePath + foundCrcList[0].list[0].path); Texture texture = new Texture(pkg, foundCrcList[0].list[0].exportID, pkg.getExportData(foundCrcList[0].list[0].exportID)); if (texture.mipMapsList.Count > 1 && image.mipMaps.Count() <= 1) { errors += "Error in texture: " + Path.GetFileName(file) + " This texture must have mipmaps, skipping texture..." + Environment.NewLine; log += "Error in texture: " + Path.GetFileName(file) + " This texture must have mipmaps, skipping texture..." + Environment.NewLine; continue; } string fmt = texture.properties.getProperty("Format").valueName; DDSFormat ddsFormat = DDSImage.convertFormat(fmt); if (image.ddsFormat != ddsFormat) { errors += "Error in texture: " + Path.GetFileName(file) + " This texture has wrong texture format, should be: " + ddsFormat + ", skipping texture..." + Environment.NewLine; log += "Error in texture: " + Path.GetFileName(file) + " This texture has wrong texture format, should be: " + ddsFormat + ", skipping texture..." + Environment.NewLine; continue; } if (image.mipMaps[0].origWidth / image.mipMaps[0].origHeight != texture.mipMapsList[0].width / texture.mipMapsList[0].height) { errors += "Error in texture: " + Path.GetFileName(file) + " This texture has wrong aspect ratio, skipping texture..." + Environment.NewLine; log += "Error in texture: " + Path.GetFileName(file) + " This texture has wrong aspect ratio, skipping texture..." + Environment.NewLine; continue; } Stream dst = compressData(src); dst.SeekBegin(); FileMod fileMod = new FileMod(); fileMod.tag = FileTextureTag; fileMod.name = Path.GetFileName(file); fileMod.offset = outFs.Position; fileMod.size = dst.Length; count++; modFiles.Add(fileMod); outFs.WriteStringASCIINull(foundCrcList[0].name); outFs.WriteUInt32(crc); outFs.WriteFromStream(dst, dst.Length); } if (count == savedCount) { continue; } } long pos = outFs.Position; outFs.SeekBegin(); outFs.WriteUInt32(TexExplorer.TextureModTag); outFs.WriteUInt32(TexExplorer.TextureModVersion); outFs.WriteInt64(pos); outFs.JumpTo(pos); outFs.WriteUInt32((uint)GameData.gameType); outFs.WriteInt32(modFiles.Count); for (int i = 0; i < modFiles.Count; i++) { outFs.WriteUInt32(modFiles[i].tag); outFs.WriteStringASCIINull(modFiles[i].name); outFs.WriteInt64(modFiles[i].offset); outFs.WriteInt64(modFiles[i].size); } } if (count == 0) { errors += "There are no texture files in " + inDir + ", mod not generated." + Environment.NewLine; log += "There are no texture files in " + inDir + ", mod not generated." + Environment.NewLine; File.Delete(outFile); } return(errors); }
public void extract(string SFARfilename, string outPath, bool ipc, ref int currentProgress, int totalNumber) { if (!File.Exists(SFARfilename)) { throw new Exception("filename missing"); } if (mainWindow != null) { mainWindow.updateStatusLabel2("Loading SFAR..."); } byte[] buffer = File.ReadAllBytes(SFARfilename); File.Delete(SFARfilename); using (FileStream outputFile = new FileStream(SFARfilename, FileMode.Create, FileAccess.Write)) { outputFile.WriteUInt32(SfarTag); outputFile.WriteUInt32(SfarVersion); outputFile.WriteUInt32(HeaderSize); outputFile.WriteUInt32(HeaderSize); outputFile.WriteUInt32(0); outputFile.WriteUInt32(HeaderSize); outputFile.WriteUInt32((uint)MaxBlockSize); outputFile.WriteUInt32(LZMATag); } using (MemoryStream stream = new MemoryStream(buffer)) { loadHeader(stream); int lastProgress = -1; for (int i = 0; i < filesCount; i++, currentProgress++) { if (filenamesIndex == i) { continue; } if (filesList[i].filenamePath == null) { throw new Exception("filename missing"); } if (mainWindow != null) { mainWindow.updateStatusLabel2("File " + (i + 1) + " of " + filesList.Count() + " - " + Path.GetFileName(filesList[i].filenamePath)); } if (installer != null) { installer.updateStatusPrepare("Unpacking DLC " + ((currentProgress + 1) * 100 / totalNumber) + "%"); } if (ipc) { int newProgress = (100 * currentProgress) / totalNumber; if (lastProgress != newProgress) { Console.WriteLine("[IPC]TASK_PROGRESS " + newProgress); Console.Out.Flush(); lastProgress = newProgress; } } int pos = filesList[i].filenamePath.IndexOf("\\BIOGame\\DLC\\", StringComparison.OrdinalIgnoreCase); string filename = filesList[i].filenamePath.Substring(pos + ("\\BIOGame\\DLC\\").Length).Replace('/', '\\'); string dir = Path.GetDirectoryName(outPath); Directory.CreateDirectory(Path.GetDirectoryName(dir + filename)); using (FileStream outputFile = new FileStream(dir + filename, FileMode.Create, FileAccess.Write)) { stream.JumpTo(filesList[i].dataOffset); if (filesList[i].compressedBlockSizesIndex == -1) { outputFile.WriteFromStream(stream, filesList[i].uncomprSize); } else { List <byte[]> uncompressedBlockBuffers = new List <byte[]>(); List <byte[]> compressedBlockBuffers = new List <byte[]>(); List <long> blockBytesLeft = new List <long>(); long bytesLeft = filesList[i].uncomprSize; for (int j = 0; j < filesList[i].numBlocks; j++) { blockBytesLeft.Add(bytesLeft); int compressedBlockSize = blockSizes[filesList[i].compressedBlockSizesIndex + j]; int uncompressedBlockSize = (int)Math.Min(bytesLeft, maxBlockSize); if (compressedBlockSize == 0) { compressedBlockSize = (int)maxBlockSize; } compressedBlockBuffers.Add(stream.ReadToBuffer(compressedBlockSize)); uncompressedBlockBuffers.Add(null); bytesLeft -= uncompressedBlockSize; } Parallel.For(0, filesList[i].numBlocks, j => { int compressedBlockSize = blockSizes[filesList[i].compressedBlockSizesIndex + (int)j]; int uncompressedBlockSize = (int)Math.Min(blockBytesLeft[(int)j], maxBlockSize); if (compressedBlockSize == 0 || compressedBlockSize == blockBytesLeft[(int)j]) { uncompressedBlockBuffers[(int)j] = compressedBlockBuffers[(int)j]; } else { uncompressedBlockBuffers[(int)j] = new SevenZipHelper.LZMA().Decompress(compressedBlockBuffers[(int)j], (uint)uncompressedBlockSize); if (uncompressedBlockBuffers[(int)j].Length == 0) { throw new Exception(); } } }); for (int j = 0; j < filesList[i].numBlocks; j++) { outputFile.WriteFromBuffer(uncompressedBlockBuffers[j]); } } } } } }