public Installer() { InitializeComponent(); Text = "MEM Installer v" + Application.ProductVersion + " for ALOT"; mipMaps = new MipMaps(); treeScan = new TreeScan(); cachePackageMgr = new CachePackageMgr(null, this); }
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); }
private string FindTextures(List <FoundTexture> textures, string packagePath, CachePackageMgr cachePackageMgr, ref string log) { string errors = ""; Package package = null; try { if (cachePackageMgr != null) { package = cachePackageMgr.OpenPackage(packagePath); } else { package = new Package(packagePath); } } catch (Exception e) { string err = ""; err += "---- Start --------------------------------------------" + Environment.NewLine; err += "Issue with open package file: " + packagePath + Environment.NewLine; err += e.Message + Environment.NewLine + Environment.NewLine; err += e.StackTrace + Environment.NewLine + Environment.NewLine; err += "---- End ----------------------------------------------" + Environment.NewLine + Environment.NewLine; errors += err; log += err; return(errors); } for (int i = 0; i < package.exportsTable.Count; i++) { int id = package.getClassNameId(package.exportsTable[i].classId); if (id == package.nameIdTexture2D || id == package.nameIdLightMapTexture2D || id == package.nameIdShadowMapTexture2D || id == package.nameIdTextureFlipBook) { Texture texture = new Texture(package, i, package.getExportData(i)); if (!texture.hasImageData()) { continue; } Texture.MipMap mipmap = texture.getTopMipmap(); string name = package.exportsTable[i].objectName; MatchedTexture matchTexture = new MatchedTexture(); bool slave = false; matchTexture.exportID = i; matchTexture.path = GameData.RelativeGameData(packagePath); if (GameData.gameType != MeType.ME1_TYPE) { slave = true; } else if (texture.packageName.ToLowerInvariant() != Path.GetFileNameWithoutExtension(package.packageFile.Name).ToLowerInvariant()) { slave = true; } uint crc = texture.getCrcTopMipmap(); if (crc == 0) { errors += "Error: Texture " + package.exportsTable[i].objectName + " is broken in package: " + packagePath + ", skipping..." + Environment.NewLine; log += "Error: Texture " + package.exportsTable[i].objectName + " is broken in package: " + packagePath + ", skipping..." + Environment.NewLine; continue; } FoundTexture foundTexName = textures.Find(s => s.crc == crc); if (foundTexName.crc != 0) { if (slave) { foundTexName.list.Add(matchTexture); } else { foundTexName.list.Insert(0, matchTexture); } } else { FoundTexture foundTex = new FoundTexture(); foundTex.list = new List <MatchedTexture>(); foundTex.list.Add(matchTexture); foundTex.name = name; foundTex.crc = crc; foundTex.packageName = texture.packageName; textures.Add(foundTex); } } } if (cachePackageMgr == null) { package.Dispose(); } else { package.DisposeCache(); } 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); }
static public bool checkGameDataModded(CachePackageMgr cachePackageMgr) { EmptyMipMaps[] entries = new EmptyMipMaps[] { new EmptyMipMaps { gameType = MeType.ME1_TYPE, packagePath = @"\BioGame\CookedPC\Packages\GameObjects\Characters\Humanoids\HumanMale\BIOG_HMM_HED_PROMorph.upk", exportId = 304, crc = 0x80B2CBCF, }, new EmptyMipMaps { gameType = MeType.ME1_TYPE, packagePath = @"\BioGame\CookedPC\Packages\GameObjects\Characters\Humanoids\HumanFemale\BIOG_HMF_HED_PROMorph_R.upk", exportId = 279, crc = 0x422AAA0D, }, new EmptyMipMaps { gameType = MeType.ME1_TYPE, packagePath = @"\BioGame\CookedPC\BIOG_ASA_ARM_MRC_R.upk", exportId = 71, crc = 0x077202BD, }, new EmptyMipMaps { gameType = MeType.ME1_TYPE, packagePath = @"\BioGame\CookedPC\Packages\GameObjects\Characters\Humanoids\HumanFemale\BIOG_HMF_HED_PROMorph_R.upk", exportId = 259, crc = 0x8F331825, }, new EmptyMipMaps { gameType = MeType.ME1_TYPE, packagePath = @"\BioGame\CookedPC\Packages\GameObjects\Characters\Humanoids\HumanFemale\BIOG_HMF_HED_PROMorph_R.upk", exportId = 262, crc = 0x2CC6F67C, }, new EmptyMipMaps { gameType = MeType.ME1_TYPE, packagePath = @"\BioGame\CookedPC\Packages\GameObjects\Characters\Humanoids\Turian\BIOG_TUR_HED_PROMorph_R.upk", exportId = 115, crc = 0x39A26907, }, new EmptyMipMaps { gameType = MeType.ME1_TYPE, packagePath = @"\BioGame\CookedPC\Packages\GameObjects\Characters\Humanoids\HumanMale\BIOG_HMM_HED_PROMorph.upk", exportId = 356, crc = 0xCD4AD3A5, }, new EmptyMipMaps { gameType = MeType.ME1_TYPE, packagePath = @"\BioGame\CookedPC\Packages\GameObjects\Characters\Humanoids\HumanMale\BIOG_HMM_HED_PROMorph.upk", exportId = 360, crc = 0x0898E4C4, }, new EmptyMipMaps { gameType = MeType.ME1_TYPE, packagePath = @"\BioGame\CookedPC\Packages\GameObjects\Characters\Humanoids\HumanFemale\BIOG_HMF_ARM_CTH_R.upk", exportId = 243, crc = 0x8D20F3EB, }, new EmptyMipMaps { gameType = MeType.ME1_TYPE, packagePath = @"\BioGame\CookedPC\Packages\GameObjects\Characters\Humanoids\Turian\BIOG_TUR_HED_SAR.upk", exportId = 51, crc = 0x4F24BAAF, }, new EmptyMipMaps { gameType = MeType.ME1_TYPE, packagePath = @"\BioGame\CookedPC\Packages\GameObjects\Characters\Humanoids\HumanMale\BIOG_HMM_HED_PROMorph.upk", exportId = 394, crc = 0x947A74A8, }, new EmptyMipMaps { gameType = MeType.ME1_TYPE, packagePath = @"\BioGame\CookedPC\Packages\GameObjects\Characters\Humanoids\HumanMale\BIOG_HMM_HED_PROMorph.upk", exportId = 341, crc = 0x72D6575F, }, new EmptyMipMaps { gameType = MeType.ME1_TYPE, packagePath = @"\BioGame\CookedPC\Packages\GameObjects\Characters\Humanoids\Krogan\BIOG_KRO_HED_PROMorph.upk", exportId = 61, crc = 0x822EEFB1, }, new EmptyMipMaps { gameType = MeType.ME2_TYPE, packagePath = @"\BioGame\CookedPC\BioA_N7Spdr2_100.pcc", exportId = 13796, crc = 0x80B2CBCF, }, new EmptyMipMaps { gameType = MeType.ME2_TYPE, packagePath = @"\BioGame\CookedPC\BioD_JunCvL_100Landing.pcc", exportId = 6105, crc = 0x72D6575F, }, new EmptyMipMaps { gameType = MeType.ME2_TYPE, packagePath = @"\BioGame\CookedPC\BioD_EndGm2_440Normandy.pcc", exportId = 2569, crc = 0xCD4AD3A5, }, new EmptyMipMaps { gameType = MeType.ME2_TYPE, packagePath = @"\BioGame\CookedPC\BioD_HorCr1_303AshKaidan.pcc", exportId = 3781, crc = 0x0898E4C4, }, new EmptyMipMaps { gameType = MeType.ME2_TYPE, packagePath = @"\BioGame\CookedPC\BIOG_HMM_HED_PROMorph.pcc", exportId = 2495, crc = 0x947A74A8, }, new EmptyMipMaps { gameType = MeType.ME2_TYPE, packagePath = @"\BioGame\CookedPC\BioD_JnkKgA_300Labs.pcc", exportId = 5785, crc = 0xECA7DA8F, }, new EmptyMipMaps { gameType = MeType.ME2_TYPE, packagePath = @"\BioGame\CookedPC\BioD_CitAsL_210FirstStop.pcc", exportId = 4117, crc = 0x822EEFB1, }, new EmptyMipMaps { gameType = MeType.ME2_TYPE, packagePath = @"\BioGame\CookedPC\BioD_EndGm1_110ROMGarrus.pcc", exportId = 5076, crc = 0x6E3C2E30, }, new EmptyMipMaps { gameType = MeType.ME2_TYPE, packagePath = @"\BioGame\CookedPC\BioD_OmgGrA_113AlamoAssault.pcc", exportId = 4864, crc = 0x6CD2B8F2, }, new EmptyMipMaps { gameType = MeType.ME2_TYPE, packagePath = @"\BioGame\CookedPC\BioH_END_Professor_00.pcc", exportId = 5894, crc = 0x9A987362, }, new EmptyMipMaps { gameType = MeType.ME2_TYPE, packagePath = @"\BioGame\CookedPC\BioD_EndGm1_110ROMMirranda.pcc", exportId = 8808, crc = 0xB389BFE6, }, new EmptyMipMaps { gameType = MeType.ME2_TYPE, packagePath = @"\BioGame\CookedPC\BIOG_HMF_HED_PROMorph_R.pcc", exportId = 3073, crc = 0x5674B1E3, }, new EmptyMipMaps { gameType = MeType.ME2_TYPE, packagePath = @"\BioGame\CookedPC\BioD_HorCr1_303AshKaidan.pcc", exportId = 3757, crc = 0x422AAA0D, }, new EmptyMipMaps { gameType = MeType.ME2_TYPE, packagePath = @"\BioGame\CookedPC\BioD_BchLmL_102BeachFight.pcc", exportId = 5869, crc = 0x9CA124E8, }, new EmptyMipMaps { gameType = MeType.ME2_TYPE, packagePath = @"\BioGame\CookedPC\BioA_N7Mmnt7.pcc", exportId = 10440, crc = 0x2A01319D, }, new EmptyMipMaps { gameType = MeType.ME2_TYPE, packagePath = @"\BioGame\CookedPC\BioD_ProNor.pcc", exportId = 21224, crc = 0x40197218, }, new EmptyMipMaps { gameType = MeType.ME2_TYPE, packagePath = @"\BioGame\CookedPC\BioD_Nor_231Morinth.pcc", exportId = 1922, crc = 0x27539E1B, }, new EmptyMipMaps { gameType = MeType.ME2_TYPE, packagePath = @"\BioGame\CookedPC\BioD_CitAsL.pcc", exportId = 8798, crc = 0x42EE7CBF, }, new EmptyMipMaps { gameType = MeType.ME2_TYPE, packagePath = @"\BioGame\CookedPC\BioD_Nor_110DebriefLeadVixen.pcc", exportId = 4433, crc = 0xD30672BD, }, new EmptyMipMaps { gameType = MeType.ME3_TYPE, packagePath = @"\BioGame\CookedPCConsole\BioA_CitSam_000LevelTrans.pcc", exportId = 4607, crc = 0x0F4E701E, }, new EmptyMipMaps { gameType = MeType.ME3_TYPE, packagePath = @"\BioGame\CookedPCConsole\BioD_CitHub_EmbassyP3.pcc", exportId = 8182, crc = 0x27539E1B, }, new EmptyMipMaps { gameType = MeType.ME3_TYPE, packagePath = @"\BioGame\CookedPCConsole\BioD_Cat003_380DesksConvos.pcc", exportId = 9460, crc = 0x42EE7CBF, }, new EmptyMipMaps { gameType = MeType.ME3_TYPE, packagePath = @"\BioGame\CookedPCConsole\BioA_GthLeg_000LevelTrans.pcc", exportId = 3500, crc = 0xD30672BD, }, new EmptyMipMaps { gameType = MeType.ME3_TYPE, packagePath = @"\BioGame\CookedPCConsole\BioA_CitHub_000Docking.pcc", exportId = 3625, crc = 0xF51672AC, }, new EmptyMipMaps { gameType = MeType.ME3_TYPE, packagePath = @"\BioGame\CookedPCConsole\BioD_CerJcb_150MainDoor.pcc", exportId = 7722, crc = 0xEDC5BFE7, }, new EmptyMipMaps { gameType = MeType.ME3_TYPE, packagePath = @"\BioGame\CookedPCConsole\BioD_CitHub_WardsFluxP3.pcc", exportId = 11443, crc = 0xF95D3472, }, new EmptyMipMaps { gameType = MeType.ME3_TYPE, packagePath = @"\BioGame\CookedPCConsole\BioD_CitHub_Dock.pcc", exportId = 11485, crc = 0xE8271883, }, new EmptyMipMaps { gameType = MeType.ME3_TYPE, packagePath = @"\BioGame\CookedPCConsole\BioD_CerMir_375Lab_vid.pcc", exportId = 4630, crc = 0x4D73F4F6, }, new EmptyMipMaps { gameType = MeType.ME3_TYPE, packagePath = @"\BioGame\CookedPCConsole\BIOG_HMF_HED_PROMorph_R.pcc", exportId = 7552, crc = 0xF6BFD7B5, }, new EmptyMipMaps { gameType = MeType.ME3_TYPE, packagePath = @"\BioGame\CookedPCConsole\BioA_MPCer_000Translevel.pcc", exportId = 6294, crc = 0x3451A823, }, new EmptyMipMaps { gameType = MeType.ME3_TYPE, packagePath = @"\BioGame\CookedPCConsole\BioA_Cat002_050Shuttle.pcc", exportId = 2995, crc = 0xF394E97A, }, new EmptyMipMaps { gameType = MeType.ME3_TYPE, packagePath = @"\BioGame\CookedPCConsole\BioD_CitHub_000ProCit.pcc", exportId = 6451, crc = 0x2DCFDEA9, }, new EmptyMipMaps { gameType = MeType.ME3_TYPE, packagePath = @"\BioGame\CookedPCConsole\BIOG_HMM_HED_PROMorph.pcc", exportId = 8818, crc = 0xB2900BF5, }, new EmptyMipMaps { gameType = MeType.ME3_TYPE, packagePath = @"\BioGame\CookedPCConsole\BioD_Cat003_780FinalConvos.pcc", exportId = 9938, crc = 0x6574CE07, }, new EmptyMipMaps { gameType = MeType.ME3_TYPE, packagePath = @"\BioGame\CookedPCConsole\BioD_Gth001_560Gethries.pcc", exportId = 7227, crc = 0x36DACF3F, }, new EmptyMipMaps { gameType = MeType.ME3_TYPE, packagePath = @"\BioGame\CookedPCConsole\BioA_Kro001_000LevelTrans.pcc", exportId = 7156, crc = 0x1198BA9D, }, new EmptyMipMaps { gameType = MeType.ME3_TYPE, packagePath = @"\BioGame\CookedPCConsole\BioD_End001_436CRGrunt.pcc", exportId = 1568, crc = 0xECA7DA8F, }, new EmptyMipMaps { gameType = MeType.ME3_TYPE, packagePath = @"\BioGame\CookedPCConsole\BioD_End001_436CRMordin.pcc", exportId = 1456, crc = 0x9A987362, }, new EmptyMipMaps { gameType = MeType.ME3_TYPE, packagePath = @"\BioGame\CookedPCConsole\BioA_CitHub_Council.pcc", exportId = 6653, crc = 0x8645A85C, }, }; for (int i = 0; i < entries.Count(); i++) { if (GameData.gameType == entries[i].gameType) { Package package = null; try { if (cachePackageMgr != null) { package = cachePackageMgr.OpenPackage(GameData.GamePath + entries[i].packagePath); } else { package = new Package(GameData.GamePath + entries[i].packagePath); } } catch { return(false); } Texture texture = new Texture(package, entries[i].exportId, package.getExportData(entries[i].exportId)); if (texture.getCrcTopMipmap() != entries[i].crc) { return(true); } } } return(false); }
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); }
private string FindTextures(List <FoundTexture> textures, string packagePath, CachePackageMgr cachePackageMgr, ref string log) { string errors = ""; Package package = null; try { if (cachePackageMgr != null) { package = cachePackageMgr.OpenPackage(packagePath); } else { package = new Package(packagePath); } } catch (Exception e) { string err = ""; err += "---- Start --------------------------------------------" + Environment.NewLine; err += "Issue with open package file: " + packagePath + Environment.NewLine; err += e.Message + Environment.NewLine + Environment.NewLine; err += e.StackTrace + Environment.NewLine + Environment.NewLine; err += "---- End ----------------------------------------------" + Environment.NewLine + Environment.NewLine; errors += err; log += err; return(errors); } for (int i = 0; i < package.exportsTable.Count; i++) { int id = package.getClassNameId(package.exportsTable[i].classId); if (id == package.nameIdTexture2D || id == package.nameIdLightMapTexture2D || id == package.nameIdShadowMapTexture2D || id == package.nameIdTextureFlipBook) { Texture texture = new Texture(package, i, package.getExportData(i)); if (!texture.hasImageData()) { continue; } Texture.MipMap mipmap = texture.getTopMipmap(); string name = package.exportsTable[i].objectName; MatchedTexture matchTexture = new MatchedTexture(); matchTexture.exportID = i; matchTexture.path = GameData.RelativeGameData(packagePath); matchTexture.packageName = texture.packageName; if (GameData.gameType == MeType.ME1_TYPE) { matchTexture.basePackageName = texture.basePackageName; matchTexture.slave = texture.slave; matchTexture.weakSlave = texture.weakSlave; matchTexture.linkToMaster = -1; if (matchTexture.slave) { matchTexture.mipmapOffset = mipmap.dataOffset; } else { matchTexture.mipmapOffset = package.exportsTable[i].dataOffset + (uint)texture.properties.propertyEndOffset + mipmap.internalOffset; } } uint crc = 0; try { crc = texture.getCrcTopMipmap(); } catch { } if (crc == 0) { errors += "Error: Texture " + package.exportsTable[i].objectName + " is broken in package: " + packagePath + ", skipping..." + Environment.NewLine; log += "Error: Texture " + package.exportsTable[i].objectName + " is broken in package: " + packagePath + ", skipping..." + Environment.NewLine; continue; } FoundTexture foundTexName = textures.Find(s => s.crc == crc); if (foundTexName.crc != 0) { if (matchTexture.slave || GameData.gameType != MeType.ME1_TYPE) { foundTexName.list.Add(matchTexture); } else { foundTexName.list.Insert(0, matchTexture); } } else { FoundTexture foundTex = new FoundTexture(); foundTex.list = new List <MatchedTexture>(); foundTex.list.Add(matchTexture); foundTex.name = name; foundTex.crc = crc; if (generateBuiltinMapFiles) { foundTex.width = texture.getTopMipmap().width; foundTex.height = texture.getTopMipmap().height; foundTex.pixfmt = Image.getEngineFormatType(texture.properties.getProperty("Format").valueName); if (foundTex.pixfmt == PixelFormat.DXT1 && texture.properties.exists("CompressionSettings") && texture.properties.getProperty("CompressionSettings").valueName == "TC_OneBitAlpha") { foundTex.alphadxt1 = true; } } textures.Add(foundTex); } } } if (cachePackageMgr == null) { 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); }
private string processTextureMod(string filenameMod, int previewIndex, bool extract, bool replace, bool verify, string outDir, List <FoundTexture> textures, CachePackageMgr cachePackageMgr, TexExplorer texExplorer, ref string log) { string errors = ""; if (filenameMod.EndsWith(".tpf", StringComparison.OrdinalIgnoreCase)) { if (!replace && !extract) { throw new Exception(); } int result; string fileName = ""; ulong dstLen = 0; string[] ddsList = null; ulong numEntries = 0; IntPtr handle = IntPtr.Zero; ZlibHelper.Zip zip = new ZlibHelper.Zip(); try { int indexTpf = -1; handle = zip.Open(filenameMod, ref numEntries, 1); for (ulong i = 0; i < numEntries; i++) { result = zip.GetCurrentFileInfo(handle, ref fileName, ref dstLen); fileName = fileName.Trim(); if (result != 0) { throw new Exception(); } if (Path.GetExtension(fileName).ToLowerInvariant() == ".def" || Path.GetExtension(fileName).ToLowerInvariant() == ".log") { indexTpf = (int)i; break; } result = zip.GoToNextFile(handle); if (result != 0) { throw new Exception(); } } byte[] listText = new byte[dstLen]; result = zip.ReadCurrentFile(handle, listText, dstLen); if (result != 0) { throw new Exception(); } ddsList = Encoding.ASCII.GetString(listText).Trim('\0').Replace("\r", "").TrimEnd('\n').Split('\n'); result = zip.GoToFirstFile(handle); if (result != 0) { throw new Exception(); } for (uint i = 0; i < numEntries; i++) { if (i == indexTpf) { result = zip.GoToNextFile(handle); continue; } try { uint crc = 0; result = zip.GetCurrentFileInfo(handle, ref fileName, ref dstLen); if (result != 0) { throw new Exception(); } fileName = fileName.Trim(); foreach (string dds in ddsList) { string ddsFile = dds.Split('|')[1]; if (ddsFile.ToLowerInvariant().Trim() != fileName.ToLowerInvariant()) { continue; } crc = uint.Parse(dds.Split('|')[0].Substring(2), System.Globalization.NumberStyles.HexNumber); break; } string filename = Path.GetFileName(fileName); if (crc == 0) { log += "Skipping file: " + filename + " not found in definition file, entry: " + (i + 1) + " - mod: " + filenameMod + Environment.NewLine; errors += "Skipping file: " + filename + " not found in definition file, entry: " + (i + 1) + " - mod: " + filenameMod + Environment.NewLine; zip.GoToNextFile(handle); continue; } FoundTexture foundTexture = textures.Find(s => s.crc == crc); if (foundTexture.crc != 0) { byte[] data = new byte[dstLen]; result = zip.ReadCurrentFile(handle, data, dstLen); if (result != 0) { log += "Error in texture: " + foundTexture.name + string.Format("_0x{0:X8}", crc) + ", skipping texture, entry: " + (i + 1) + " - mod: " + filenameMod + Environment.NewLine; errors += "Error in texture: " + foundTexture.name + string.Format("_0x{0:X8}", crc) + ", skipping texture, entry: " + (i + 1) + " - mod: " + filenameMod + Environment.NewLine; zip.GoToNextFile(handle); continue; } if (texExplorer != null) { texExplorer._mainWindow.updateStatusLabel("Processing MOD " + Path.GetFileName(filenameMod) + " - File " + (i + 1) + " of " + numEntries + " - " + foundTexture.name); } if (extract) { string name = foundTexture.name + "_" + string.Format("0x{0:X8}", crc) + Path.GetExtension(fileName); using (FileStream output = new FileStream(Path.Combine(outDir, name), FileMode.Create, FileAccess.Write)) { output.Write(data, 0, (int)dstLen); } } else { Image image = new Image(data, Path.GetExtension(filename)); errors += replaceTexture(image, foundTexture.list, cachePackageMgr, foundTexture.name, crc, verify); } } else { log += "Texture skipped. File " + filename + string.Format(" - 0x{0:X8}", crc) + " is not present in your game setup - mod: " + filenameMod + Environment.NewLine; zip.GoToNextFile(handle); continue; } } catch { log += "Skipping not compatible content, entry: " + (i + 1) + " file: " + fileName + " - mod: " + filenameMod + Environment.NewLine; errors += "Skipping not compatible content, entry: " + (i + 1) + " file: " + fileName + " - mod: " + filenameMod + Environment.NewLine; } result = zip.GoToNextFile(handle); } zip.Close(handle); handle = IntPtr.Zero; } catch { log += "Mod is not compatible: " + filenameMod + Environment.NewLine; errors += "Mod is not compatible: " + filenameMod + Environment.NewLine; if (handle != IntPtr.Zero) { zip.Close(handle); } handle = IntPtr.Zero; } return(errors); } else if (filenameMod.EndsWith(".mod", StringComparison.OrdinalIgnoreCase)) { if (!replace && !extract) { throw new Exception(); } try { using (FileStream fs = new FileStream(filenameMod, FileMode.Open, FileAccess.Read)) { string package = ""; int len = fs.ReadInt32(); string version = fs.ReadStringASCIINull(); if (version.Length < 5) // legacy .mod { fs.SeekBegin(); } else { fs.SeekBegin(); len = fs.ReadInt32(); version = fs.ReadStringASCII(len); // version } uint numEntries = fs.ReadUInt32(); for (uint i = 0; i < numEntries; i++) { TexExplorer.BinaryMod mod = new TexExplorer.BinaryMod(); len = fs.ReadInt32(); string desc = fs.ReadStringASCII(len); // description len = fs.ReadInt32(); string scriptLegacy = fs.ReadStringASCII(len); string path = ""; if (desc.Contains("Binary Replacement")) { try { Misc.ParseME3xBinaryScriptMod(scriptLegacy, ref package, ref mod.exportId, ref path); if (mod.exportId == -1 || package == "" || path == "") { throw new Exception(); } } catch { len = fs.ReadInt32(); fs.Skip(len); errors += "Skipping not compatible content, entry: " + (i + 1) + " - mod: " + filenameMod + Environment.NewLine; continue; } mod.packagePath = Path.Combine(GameData.GamePath + path, package); len = fs.ReadInt32(); mod.data = fs.ReadToBuffer(len); if (!File.Exists(mod.packagePath)) { errors += "Warning: File " + mod.packagePath + " not exists in your game setup." + Environment.NewLine; log += "Warning: File " + mod.packagePath + " not exists in your game setup." + Environment.NewLine; continue; } Package pkg = cachePackageMgr.OpenPackage(mod.packagePath); pkg.setExportData(mod.exportId, mod.data); } else { string textureName = desc.Split(' ').Last(); FoundTexture f; try { f = Misc.ParseLegacyMe3xScriptMod(textures, scriptLegacy, textureName); mod.textureCrc = f.crc; if (mod.textureCrc == 0) { throw new Exception(); } } catch { len = fs.ReadInt32(); fs.Skip(len); errors += "Skipping not compatible content, entry: " + (i + 1) + " - mod: " + filenameMod + Environment.NewLine; continue; } textureName = f.name; mod.textureName = textureName; len = fs.ReadInt32(); mod.data = fs.ReadToBuffer(len); PixelFormat pixelFormat = f.pixfmt; Image image = new Image(mod.data, Image.ImageFormat.DDS); errors += replaceTexture(image, f.list, cachePackageMgr, f.name, f.crc, verify); } } } } catch { errors += "Mod is not compatible: " + filenameMod + Environment.NewLine; } return(errors); } using (FileStream fs = new FileStream(filenameMod, FileMode.Open, FileAccess.Read)) { if (previewIndex == -1 && !extract && !replace) { texExplorer.listViewTextures.BeginUpdate(); } uint tag = fs.ReadUInt32(); uint version = fs.ReadUInt32(); if (tag != TexExplorer.TextureModTag || version != TexExplorer.TextureModVersion) { if (version != TexExplorer.TextureModVersion) { errors += "File " + filenameMod + " was made with an older version of MEM, skipping..." + Environment.NewLine; log += "File " + filenameMod + " was made with an older version of MEM, skipping..." + Environment.NewLine; } else { errors += "File " + filenameMod + " is not a valid MEM mod, skipping..." + Environment.NewLine; log += "File " + filenameMod + " is not a valid MEM mod, skipping..." + Environment.NewLine; } if (previewIndex == -1 && !extract && !replace) { texExplorer.listViewTextures.EndUpdate(); } return(errors); } else { uint gameType = 0; fs.JumpTo(fs.ReadInt64()); gameType = fs.ReadUInt32(); if (textures != null && (MeType)gameType != GameData.gameType) { errors += "File " + filenameMod + " is not a MEM mod valid for this game" + Environment.NewLine; log += "File " + filenameMod + " is not a MEM mod valid for this game" + Environment.NewLine; if (previewIndex == -1 && !extract && !replace) { texExplorer.listViewTextures.EndUpdate(); } return(errors); } } int numFiles = fs.ReadInt32(); List <FileMod> modFiles = new List <FileMod>(); for (int i = 0; i < numFiles; i++) { FileMod fileMod = new FileMod(); fileMod.tag = fs.ReadUInt32(); fileMod.name = fs.ReadStringASCIINull(); fileMod.offset = fs.ReadInt64(); fileMod.size = fs.ReadInt64(); modFiles.Add(fileMod); } numFiles = modFiles.Count; for (int i = 0; i < numFiles; i++) { string name = ""; uint crc = 0; long size = 0, dstLen = 0; int exportId = -1; string pkgPath = ""; byte[] dst = null; if (previewIndex != -1) { i = previewIndex; } fs.JumpTo(modFiles[i].offset); size = modFiles[i].size; if (modFiles[i].tag == FileTextureTag) { name = fs.ReadStringASCIINull(); crc = fs.ReadUInt32(); } else if (modFiles[i].tag == FileBinaryTag) { name = modFiles[i].name; exportId = fs.ReadInt32(); pkgPath = fs.ReadStringASCIINull(); } if (texExplorer != null) { texExplorer._mainWindow.updateStatusLabel("Processing MOD " + Path.GetFileName(filenameMod) + " - File " + (i + 1) + " of " + numFiles + " - " + name); } if (previewIndex == -1 && !extract && !replace) { if (modFiles[i].tag == FileTextureTag) { FoundTexture foundTexture; foundTexture = textures.Find(s => s.crc == crc); if (foundTexture.crc != 0) { ListViewItem item = new ListViewItem(foundTexture.name + " (" + Path.GetFileNameWithoutExtension(foundTexture.list[0].path).ToUpperInvariant() + ")"); item.Name = i.ToString(); texExplorer.listViewTextures.Items.Add(item); } else { ListViewItem item = new ListViewItem(name + " (Texture not found: " + name + string.Format("_0x{0:X8}", crc) + ")"); item.Name = i.ToString(); texExplorer.listViewTextures.Items.Add(item); log += "Texture skipped. Texture " + name + string.Format("_0x{0:X8}", crc) + " is not present in your game setup" + Environment.NewLine; } } else if (modFiles[i].tag == FileBinaryTag) { ListViewItem item = new ListViewItem(name + " (Binary Mod)"); item.Name = i.ToString(); texExplorer.listViewTextures.Items.Add(item); } else { ListViewItem item = new ListViewItem(name + " (Unknown)"); item.Name = i.ToString(); errors += "Unknown tag for file: " + name + Environment.NewLine; log += "Unknown tag for file: " + name + Environment.NewLine; } continue; } dst = decompressData(fs, size); dstLen = dst.Length; if (extract) { if (modFiles[i].tag == FileTextureTag) { string filename = name + "_" + string.Format("0x{0:X8}", crc) + ".dds"; using (FileStream output = new FileStream(Path.Combine(outDir, Path.GetFileName(filename)), FileMode.Create, FileAccess.Write)) { output.Write(dst, 0, (int)dstLen); } } else if (modFiles[i].tag == FileBinaryTag) { string path = pkgPath; string newFilename; if (path.Contains("\\DLC\\")) { string dlcName = path.Split('\\')[3]; newFilename = "D" + dlcName.Length + "-" + dlcName + "-"; } else { newFilename = "B"; } newFilename += Path.GetFileName(path).Length + "-" + Path.GetFileName(path) + "-E" + exportId + ".bin"; using (FileStream output = new FileStream(Path.Combine(outDir, newFilename), FileMode.Create, FileAccess.Write)) { output.Write(dst, 0, (int)dstLen); } } else { errors += "Unknown tag for file: " + name + Environment.NewLine; log += "Unknown tag for file: " + name + Environment.NewLine; } continue; } if (previewIndex != -1) { if (modFiles[i].tag == FileTextureTag) { Image image = new Image(dst, Image.ImageFormat.DDS); texExplorer.pictureBoxPreview.Image = image.getBitmapARGB(); } else { texExplorer.pictureBoxPreview.Image = null; } break; } else if (replace) { if (modFiles[i].tag == FileTextureTag) { FoundTexture foundTexture; foundTexture = textures.Find(s => s.crc == crc); if (foundTexture.crc != 0) { Image image = new Image(dst, Image.ImageFormat.DDS); errors += replaceTexture(image, foundTexture.list, cachePackageMgr, foundTexture.name, crc, verify); } else { log += "Error: Texture " + name + string.Format("_0x{0:X8}", crc) + "is not present in your game setup. Texture skipped." + Environment.NewLine; } } else if (modFiles[i].tag == FileBinaryTag) { string path = GameData.GamePath + pkgPath; if (!File.Exists(path)) { errors += "Warning: File " + path + " not exists in your game setup." + Environment.NewLine; log += "Warning: File " + path + " not exists in your game setup." + Environment.NewLine; continue; } Package pkg = cachePackageMgr.OpenPackage(path); pkg.setExportData(exportId, dst); } else { errors += "Error: Unknown tag for file: " + name + Environment.NewLine; log += "Error: Unknown tag for file: " + name + Environment.NewLine; } } else { throw new Exception(); } } if (previewIndex == -1 && !extract && !replace) { texExplorer.listViewTextures.EndUpdate(); } } return(errors); }
public string listTextureMod(string filenameMod, List <FoundTexture> textures, CachePackageMgr cachePackageMgr, TexExplorer texExplorer, ref string log) { return(processTextureMod(filenameMod, -1, false, false, false, "", textures, cachePackageMgr, texExplorer, ref log)); }
public string replaceTextureMod(string filenameMod, List <FoundTexture> textures, CachePackageMgr cachePackageMgr, TexExplorer texExplorer, bool verify, ref string log) { return(processTextureMod(filenameMod, -1, false, true, verify, "", textures, cachePackageMgr, texExplorer, ref log)); }
public string previewTextureMod(string filenameMod, int previewIndex, List <FoundTexture> textures, CachePackageMgr cachePackageMgr, TexExplorer texExplorer, ref string log) { return(processTextureMod(filenameMod, previewIndex, false, false, false, "", textures, cachePackageMgr, texExplorer, ref log)); }
public string extractTextureMod(string filenameMod, string outDir, List <FoundTexture> textures, CachePackageMgr cachePackageMgr, TexExplorer texExplorer, ref string log) { return(processTextureMod(filenameMod, -1, true, false, false, outDir, textures, cachePackageMgr, texExplorer, ref log)); }
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(""); } }
private string processTextureMod(string filenameMod, int previewIndex, bool extract, bool replace, string outDir, List <FoundTexture> textures, CachePackageMgr cachePackageMgr, TexExplorer texExplorer, ref string log) { string errors = ""; using (FileStream fs = new FileStream(filenameMod, FileMode.Open, FileAccess.Read)) { if (previewIndex == -1 && !extract && !replace) { texExplorer.listViewTextures.BeginUpdate(); } uint tag = fs.ReadUInt32(); uint version = fs.ReadUInt32(); if (tag != TexExplorer.TextureModTag || version != TexExplorer.TextureModVersion) { if (version != TexExplorer.TextureModVersion) { errors += "File " + filenameMod + " was made with an older version of MEM, skipping..." + Environment.NewLine; log += "File " + filenameMod + " was made with an older version of MEM, skipping..." + Environment.NewLine; } else { errors += "File " + filenameMod + " is not a valid MEM mod, skipping..." + Environment.NewLine; log += "File " + filenameMod + " is not a valid MEM mod, skipping..." + Environment.NewLine; } if (previewIndex == -1 && !extract && !replace) { texExplorer.listViewTextures.EndUpdate(); } return(errors); } else { uint gameType = 0; fs.JumpTo(fs.ReadInt64()); gameType = fs.ReadUInt32(); if (textures != null && (MeType)gameType != GameData.gameType) { errors += "File " + filenameMod + " is not a MEM mod valid for this game" + Environment.NewLine; log += "File " + filenameMod + " is not a MEM mod valid for this game" + Environment.NewLine; if (previewIndex == -1 && !extract && !replace) { texExplorer.listViewTextures.EndUpdate(); } return(errors); } } int numFiles = fs.ReadInt32(); List <FileMod> modFiles = new List <FileMod>(); for (int i = 0; i < numFiles; i++) { FileMod fileMod = new FileMod(); fileMod.tag = fs.ReadUInt32(); fileMod.name = fs.ReadStringASCIINull(); fileMod.offset = fs.ReadInt64(); fileMod.size = fs.ReadInt64(); modFiles.Add(fileMod); } numFiles = modFiles.Count; for (int i = 0; i < numFiles; i++) { string name = ""; uint crc = 0; long size = 0, dstLen = 0; int exportId = -1; string pkgPath = ""; byte[] dst = null; if (previewIndex != -1) { i = previewIndex; } fs.JumpTo(modFiles[i].offset); size = modFiles[i].size; if (modFiles[i].tag == FileTextureTag) { name = fs.ReadStringASCIINull(); crc = fs.ReadUInt32(); } else if (modFiles[i].tag == FileBinaryTag) { name = modFiles[i].name; exportId = fs.ReadInt32(); pkgPath = fs.ReadStringASCIINull(); } if (texExplorer != null) { texExplorer._mainWindow.updateStatusLabel("Processing MOD " + Path.GetFileName(filenameMod) + " - File " + (i + 1) + " of " + numFiles + " - " + name); } if (previewIndex == -1 && !extract && !replace) { if (modFiles[i].tag == FileTextureTag) { FoundTexture foundTexture; foundTexture = textures.Find(s => s.crc == crc); if (foundTexture.crc != 0) { ListViewItem item = new ListViewItem(foundTexture.name + " (" + foundTexture.packageName + ")"); item.Name = i.ToString(); texExplorer.listViewTextures.Items.Add(item); } else { ListViewItem item = new ListViewItem(name + " (Texture not found: " + name + string.Format("_0x{0:X8}", crc) + ")"); item.Name = i.ToString(); texExplorer.listViewTextures.Items.Add(item); log += "Texture skipped. Texture " + name + string.Format("_0x{0:X8}", crc) + " is not present in your game setup" + Environment.NewLine; } } else if (modFiles[i].tag == FileBinaryTag) { ListViewItem item = new ListViewItem(name + " (Binary Mod)"); item.Name = i.ToString(); texExplorer.listViewTextures.Items.Add(item); } else { ListViewItem item = new ListViewItem(name + " (Unknown)"); item.Name = i.ToString(); errors += "Unknown tag for file: " + name + Environment.NewLine; log += "Unknown tag for file: " + name + Environment.NewLine; } continue; } dst = decompressData(fs, size); dstLen = dst.Length; if (extract) { if (modFiles[i].tag == FileTextureTag) { string filename = name + "_" + string.Format("0x{0:X8}", crc) + ".dds"; using (FileStream output = new FileStream(Path.Combine(outDir, Path.GetFileName(filename)), FileMode.Create, FileAccess.Write)) { output.Write(dst, 0, (int)dstLen); } } else if (modFiles[i].tag == FileBinaryTag) { string filename = name; using (FileStream output = new FileStream(Path.Combine(outDir, Path.GetFileName(filename)), FileMode.Create, FileAccess.Write)) { output.Write(dst, 0, (int)dstLen); } } else { errors += "Unknown tag for file: " + name + Environment.NewLine; log += "Unknown tag for file: " + name + Environment.NewLine; } continue; } if (previewIndex != -1) { if (modFiles[i].tag == FileTextureTag) { DDSImage image = new DDSImage(new MemoryStream(dst, 0, (int)dstLen)); texExplorer.pictureBoxPreview.Image = image.mipMaps[0].bitmap; } else { texExplorer.pictureBoxPreview.Image = null; } break; } else if (replace) { if (modFiles[i].tag == FileTextureTag) { FoundTexture foundTexture; foundTexture = textures.Find(s => s.crc == crc); if (foundTexture.crc != 0) { DDSImage image = new DDSImage(new MemoryStream(dst, 0, (int)dstLen)); if (!image.checkExistAllMipmaps()) { errors += "Error in texture: " + name + string.Format("_0x{0:X8}", crc) + " Texture skipped. This texture has not all the required mipmaps." + Environment.NewLine; log += "Error in texture: " + name + string.Format("_0x{0:X8}", crc) + " Texture skipped. This texture has not all the required mipmaps." + Environment.NewLine; continue; } errors += replaceTexture(image, foundTexture.list, cachePackageMgr, foundTexture.name, crc); } else { log += "Error: Texture " + name + string.Format("_0x{0:X8}", crc) + "is not present in your game setup. Texture skipped." + Environment.NewLine; } } else if (modFiles[i].tag == FileBinaryTag) { string path = GameData.GamePath + pkgPath; if (!File.Exists(path)) { errors += "Warning: File " + path + " not exists in your game setup." + Environment.NewLine; log += "Warning: File " + path + " not exists in your game setup." + Environment.NewLine; continue; } Package pkg = cachePackageMgr.OpenPackage(path); pkg.setExportData(exportId, dst); } else { errors += "Error: Unknown tag for file: " + name + Environment.NewLine; log += "Error: Unknown tag for file: " + name + Environment.NewLine; } } else { throw new Exception(); } } if (previewIndex == -1 && !extract && !replace) { texExplorer.listViewTextures.EndUpdate(); } } return(errors); }
public string replaceTexture(DDSImage image, List <MatchedTexture> list, CachePackageMgr cachePackageMgr, string textureName, uint crc) { List <Texture> masterTextures = new List <Texture>(); Texture arcTexture = null, cprTexture = null; string errors = ""; for (int n = 0; n < list.Count; n++) { MatchedTexture nodeTexture = list[n]; Package package = cachePackageMgr.OpenPackage(GameData.GamePath + nodeTexture.path); Texture texture = new Texture(package, nodeTexture.exportID, package.getExportData(nodeTexture.exportID)); while (texture.mipMapsList.Exists(s => s.storageType == Texture.StorageTypes.empty)) { texture.mipMapsList.Remove(texture.mipMapsList.First(s => s.storageType == Texture.StorageTypes.empty)); } bool master = true; if (GameData.gameType == MeType.ME1_TYPE) { if (texture.packageName.ToLowerInvariant() != Path.GetFileNameWithoutExtension(package.packageFile.Name).ToLowerInvariant()) { master = false; if (!masterTextures.Exists(s => s.packageName.ToLowerInvariant() == texture.packageName.ToLowerInvariant())) { errors += "Error in texture: " + textureName + " Broken game file: " + nodeTexture.path + ", skipping texture..." + Environment.NewLine; continue; } } } if (texture.mipMapsList.Count > 1 && image.mipMaps.Count() <= 1) { errors += "Error in texture: " + textureName + " This texture has not all the required mipmaps, skipping texture..." + Environment.NewLine; break; } string fmt = texture.properties.getProperty("Format").valueName; DDSFormat ddsFormat = DDSImage.convertFormat(fmt); if (image.ddsFormat != ddsFormat) { errors += "Error in texture: " + textureName + " This texture has wrong texture format, should be: " + ddsFormat + ", skipping texture..." + Environment.NewLine; break; } if (image.mipMaps[0].origWidth / image.mipMaps[0].origHeight != texture.mipMapsList[0].width / texture.mipMapsList[0].height) { errors += "Error in texture: " + textureName + " This texture has wrong aspect ratio, skipping texture..." + Environment.NewLine; break; } // remove lower mipmaps from source image which not exist in game data for (int t = 0; t < image.mipMaps.Count(); t++) { if (image.mipMaps[t].origWidth <= texture.mipMapsList[0].width && image.mipMaps[t].origHeight <= texture.mipMapsList[0].height && texture.mipMapsList.Count > 1) { if (!texture.mipMapsList.Exists(m => m.width == image.mipMaps[t].origWidth && m.height == image.mipMaps[t].origHeight)) { image.mipMaps.RemoveAt(t--); } } } bool skip = false; // reuse lower mipmaps from game data which not exist in source image for (int t = 0; t < texture.mipMapsList.Count; t++) { if (texture.mipMapsList[t].width <= image.mipMaps[0].origWidth && texture.mipMapsList[t].height <= image.mipMaps[0].origHeight) { if (!image.mipMaps.Exists(m => m.origWidth == texture.mipMapsList[t].width && m.origHeight == texture.mipMapsList[t].height)) { byte[] data = texture.getMipMapData(texture.mipMapsList[t]); if (data == null) { errors += "Error in game data: " + nodeTexture.path + ", skipping texture..." + Environment.NewLine; skip = true; break; } DDSImage.MipMap mipmap = new DDSImage.MipMap(data, ddsFormat, texture.mipMapsList[t].width, texture.mipMapsList[t].height); image.mipMaps.Add(mipmap); } } } if (skip) { continue; } package.DisposeCache(); bool triggerCacheArc = false, triggerCacheCpr = false; string archiveFile = ""; byte[] origGuid = new byte[16]; if (texture.properties.exists("TextureFileCacheName")) { Array.Copy(texture.properties.getProperty("TFCFileGuid").valueStruct, origGuid, 16); string archive = texture.properties.getProperty("TextureFileCacheName").valueName; archiveFile = Path.Combine(GameData.MainData, archive + ".tfc"); if (nodeTexture.path.ToLowerInvariant().Contains("\\dlc")) { string DLCArchiveFile = Path.Combine(Path.GetDirectoryName(GameData.GamePath + nodeTexture.path), archive + ".tfc"); if (File.Exists(DLCArchiveFile)) { archiveFile = DLCArchiveFile; } else if (!File.Exists(archiveFile)) { List <string> files = Directory.GetFiles(GameData.bioGamePath, archive + ".tfc", SearchOption.AllDirectories).Where(item => item.EndsWith(".tfc", StringComparison.OrdinalIgnoreCase)).ToList(); if (files.Count == 0) { archiveFile = Path.Combine(GameData.MainData, "Textures.tfc"); } else if (files.Count == 1) { archiveFile = files[0]; } else { throw new Exception(""); } } } long fileLength = new FileInfo(archiveFile).Length; if (fileLength + 0x5000000 > 0x80000000) { archiveFile = ""; foreach (TFCTexture newGuid in guids) { archiveFile = Path.Combine(GameData.MainData, newGuid.name + ".tfc"); if (!File.Exists(archiveFile)) { texture.properties.setNameValue("TextureFileCacheName", newGuid.name); texture.properties.setStructValue("TFCFileGuid", "Guid", newGuid.guid); using (FileStream fs = new FileStream(archiveFile, FileMode.CreateNew, FileAccess.Write)) { fs.WriteFromBuffer(newGuid.guid); } break; } else { fileLength = new FileInfo(archiveFile).Length; if (fileLength + 0x5000000 < 0x80000000) { texture.properties.setNameValue("TextureFileCacheName", newGuid.name); texture.properties.setStructValue("TFCFileGuid", "Guid", newGuid.guid); break; } } archiveFile = ""; } if (archiveFile == "") { throw new Exception("No free TFC texture file!"); } } } List <Texture.MipMap> mipmaps = new List <Texture.MipMap>(); for (int m = 0; m < image.mipMaps.Count(); m++) { Texture.MipMap mipmap = new Texture.MipMap(); mipmap.width = image.mipMaps[m].origWidth; mipmap.height = image.mipMaps[m].origHeight; if (texture.existMipmap(mipmap.width, mipmap.height)) { mipmap.storageType = texture.getMipmap(mipmap.width, mipmap.height).storageType; } else { mipmap.storageType = texture.getTopMipmap().storageType; if (GameData.gameType == MeType.ME1_TYPE && master == false) { if (mipmap.storageType == Texture.StorageTypes.pccUnc || mipmap.storageType == Texture.StorageTypes.pccLZO || mipmap.storageType == Texture.StorageTypes.pccZlib) { mipmap.storageType = Texture.StorageTypes.extLZO; } } else if (GameData.gameType == MeType.ME2_TYPE || GameData.gameType == MeType.ME3_TYPE) { if (texture.properties.exists("TextureFileCacheName") && texture.mipMapsList.Count > 1) { if (texture.mipMapsList.Count < 6) { mipmap.storageType = Texture.StorageTypes.pccUnc; if (!texture.properties.exists("NeverStream")) { if (package.existsNameId("NeverStream")) { texture.properties.addBoolValue("NeverStream", true); } else { goto skip; } } } else { if (GameData.gameType == MeType.ME2_TYPE) { mipmap.storageType = Texture.StorageTypes.extLZO; } else { mipmap.storageType = Texture.StorageTypes.extZlib; } } } } } if (mipmap.storageType == Texture.StorageTypes.extLZO) { mipmap.storageType = Texture.StorageTypes.extZlib; } if (mipmap.storageType == Texture.StorageTypes.pccLZO) { mipmap.storageType = Texture.StorageTypes.pccZlib; } mipmap.uncompressedSize = image.mipMaps[m].data.Length; if (GameData.gameType == MeType.ME1_TYPE) { if (mipmap.storageType == Texture.StorageTypes.pccLZO || mipmap.storageType == Texture.StorageTypes.pccZlib) { if (master) { mipmap.newData = texture.compressTexture(image.mipMaps[m].data, mipmap.storageType); } else { mipmap.newData = masterTextures.Find(s => s.packageName.ToLowerInvariant() == texture.packageName.ToLowerInvariant()).mipMapsList[m].newData; } mipmap.compressedSize = mipmap.newData.Length; } if (mipmap.storageType == Texture.StorageTypes.pccUnc) { mipmap.compressedSize = mipmap.uncompressedSize; mipmap.newData = image.mipMaps[m].data; } if ((mipmap.storageType == Texture.StorageTypes.extLZO || mipmap.storageType == Texture.StorageTypes.extZlib) && master == false) { mipmap.compressedSize = masterTextures.Find(s => s.packageName.ToLowerInvariant() == texture.packageName.ToLowerInvariant()).mipMapsList[m].compressedSize; mipmap.dataOffset = masterTextures.Find(s => s.packageName.ToLowerInvariant() == texture.packageName.ToLowerInvariant()).mipMapsList[m].dataOffset; } } else { if (mipmap.storageType == Texture.StorageTypes.extZlib || mipmap.storageType == Texture.StorageTypes.extLZO) { if (cprTexture == null || (cprTexture != null && mipmap.storageType != cprTexture.mipMapsList[m].storageType)) { mipmap.newData = texture.compressTexture(image.mipMaps[m].data, mipmap.storageType); triggerCacheCpr = true; } else { if (cprTexture.mipMapsList[m].width != mipmap.width || cprTexture.mipMapsList[m].height != mipmap.height) { throw new Exception(); } mipmap.newData = cprTexture.mipMapsList[m].newData; } mipmap.compressedSize = mipmap.newData.Length; } if (mipmap.storageType == Texture.StorageTypes.pccUnc || mipmap.storageType == Texture.StorageTypes.extUnc) { mipmap.compressedSize = mipmap.uncompressedSize; mipmap.newData = image.mipMaps[m].data; } if (mipmap.storageType == Texture.StorageTypes.extZlib || mipmap.storageType == Texture.StorageTypes.extLZO || mipmap.storageType == Texture.StorageTypes.extUnc) { if (arcTexture == null || !StructuralComparisons.StructuralEqualityComparer.Equals( arcTexture.properties.getProperty("TFCFileGuid").valueStruct, texture.properties.getProperty("TFCFileGuid").valueStruct)) { triggerCacheArc = true; Texture.MipMap oldMipmap = texture.getMipmap(mipmap.width, mipmap.height); if (StructuralComparisons.StructuralEqualityComparer.Equals(origGuid, texture.properties.getProperty("TFCFileGuid").valueStruct) && oldMipmap.width != 0 && mipmap.newData.Length <= oldMipmap.compressedSize) { try { using (FileStream fs = new FileStream(archiveFile, FileMode.Open, FileAccess.Write)) { fs.JumpTo(oldMipmap.dataOffset); mipmap.dataOffset = oldMipmap.dataOffset; fs.WriteFromBuffer(mipmap.newData); } } catch { throw new Exception("Problem with access to TFC file: " + archiveFile); } } else { try { using (FileStream fs = new FileStream(archiveFile, FileMode.Open, FileAccess.Write)) { fs.SeekEnd(); mipmap.dataOffset = (uint)fs.Position; fs.WriteFromBuffer(mipmap.newData); } } catch { throw new Exception("Problem with access to TFC file: " + archiveFile); } } } else { if (arcTexture.mipMapsList[m].width != mipmap.width || arcTexture.mipMapsList[m].height != mipmap.height) { throw new Exception(); } mipmap.dataOffset = arcTexture.mipMapsList[m].dataOffset; } } } mipmap.width = image.mipMaps[m].width; mipmap.height = image.mipMaps[m].height; mipmaps.Add(mipmap); if (texture.mipMapsList.Count() == 1) { break; } } texture.replaceMipMaps(mipmaps); texture.properties.setIntValue("SizeX", texture.mipMapsList.First().width); texture.properties.setIntValue("SizeY", texture.mipMapsList.First().height); if (texture.properties.exists("MipTailBaseIdx")) { texture.properties.setIntValue("MipTailBaseIdx", texture.mipMapsList.Count() - 1); } if (GameData.gameType == MeType.ME1_TYPE && crc == 0x39A26907) { if (!texture.properties.exists("LODGroup")) { texture.properties.addByteValue("LODGroup", "TEXTUREGROUP_Character", 1025); } else { texture.properties.setByteValue("LODGroup", "TEXTUREGROUP_Character", 1025); } } using (MemoryStream newData = new MemoryStream()) { newData.WriteFromBuffer(texture.properties.toArray()); newData.WriteFromBuffer(texture.toArray(0)); // filled later package.setExportData(nodeTexture.exportID, newData.ToArray()); } using (MemoryStream newData = new MemoryStream()) { newData.WriteFromBuffer(texture.properties.toArray()); newData.WriteFromBuffer(texture.toArray(package.exportsTable[nodeTexture.exportID].dataOffset + (uint)newData.Position)); package.setExportData(nodeTexture.exportID, newData.ToArray()); } if (GameData.gameType == MeType.ME1_TYPE) { if (master) { masterTextures.Add(texture); } } else { if (triggerCacheCpr) { cprTexture = texture; } if (triggerCacheArc) { arcTexture = texture; } } skip: package = null; } masterTextures = null; arcTexture = cprTexture = null; return(errors); }