private void buttonMetaSave_Click(object sender, EventArgs e) { SaveFileDialog SaveMeta = new SaveFileDialog(); SaveMeta.Filter = "Metadata XML|*.xml"; DialogResult SaveResult = SaveMeta.ShowDialog(); if (SaveResult != DialogResult.OK) return; ModEntry modMetaData = new ModEntry(); modMetaData.Name = textModName.Text; modMetaData.Author = textModAuthor.Text; modMetaData.Version = textModVersion.Text; modMetaData.MGSVersion = comboForVersion.Text; modMetaData.Website = textModWebsite.Text; modMetaData.Description = textModDescription.Text; modMetaData.SaveToFile(SaveMeta.FileName); }
private void buttonBuild_Click(object sender, EventArgs e) { SaveFileDialog saveMod = new SaveFileDialog(); saveMod.Filter = "MGSV Mod|*.mgsv"; DialogResult saveResult = saveMod.ShowDialog(); if (saveResult != DialogResult.OK) return; string modPath = saveMod.FileName; ModEntry modMetaData = new ModEntry(); modMetaData.Name = textModName.Text; modMetaData.Author = textModAuthor.Text; modMetaData.Version = textModVersion.Text; modMetaData.MGSVersion = comboForVersion.Text; modMetaData.Website = textModWebsite.Text; modMetaData.Description = textModDescription.Text; modMetaData.SaveToFile(textModPath.Text + "\\metadata.xml"); Build.BuildArchive(textModPath.Text, modMetaData, modPath); MessageBox.Show("Build successful.", "MakeBite", MessageBoxButtons.OK, MessageBoxIcon.Information); }
private void buttonMetaLoad_Click(object sender, EventArgs e) { OpenFileDialog LoadMeta = new OpenFileDialog(); LoadMeta.Filter = "Metadata XML|*.xml"; DialogResult LoadResult = LoadMeta.ShowDialog(); if (LoadResult != DialogResult.OK) return; ModEntry modMetaData = new ModEntry(); modMetaData.ReadFromFile(LoadMeta.FileName); textModName.Text = modMetaData.Name; textModVersion.Text = modMetaData.Version; textModAuthor.Text = modMetaData.Author; textModWebsite.Text = modMetaData.Website; textModDescription.Text = modMetaData.Description.Replace("\n", "\r\n"); foreach(string li in comboForVersion.Items) { if(modMetaData.MGSVersion == li) { comboForVersion.SelectedIndex = comboForVersion.Items.IndexOf(li); break; } } }
public static void BuildArchive(string SourceDir, ModEntry metaData, string OutputFile) { if (Directory.Exists("_build")) Directory.Delete("_build", true); // build FPKs metaData.ModFpkEntries = new List<ModFpkEntry>(); foreach (string FpkDir in ListFpkFolders(SourceDir)) { foreach (ModFpkEntry fpkEntry in BuildFpk(FpkDir, SourceDir)) { metaData.ModFpkEntries.Add(fpkEntry); } } // build QAR entries metaData.ModQarEntries = new List<ModQarEntry>(); foreach (string qarFile in ListQarFiles(SourceDir)) { string subDir = qarFile.Substring(0, qarFile.LastIndexOf("\\")); // the subdirectory for XML output subDir = subDir.Substring(SourceDir.Length); string qarFilePath = Tools.ToQarPath(qarFile.Substring(SourceDir.Length)); if (!Directory.Exists("_build" + subDir)) Directory.CreateDirectory("_build" + subDir); // create file structure File.Copy(qarFile, "_build" + qarFile.Substring(SourceDir.Length), true); metaData.ModQarEntries.Add(new ModQarEntry() { FilePath = qarFilePath, Compressed = qarFile.Substring(qarFile.LastIndexOf(".") + 1).Contains("fpk") ? true : false, ContentHash = Tools.HashFile(qarFile) }); } metaData.SBVersion = "400"; // 0.4.0.0 metaData.SaveToFile("_build\\metadata.xml"); // build archive FastZip zipper = new FastZip(); zipper.CreateZip(OutputFile, "_build", true, "(.*?)"); Directory.Delete("_build", true); }
public void ProcessUninstallMod(ModEntry mod) { ProgressWindow.Show("Uninstalling Mod", String.Format("Uninstalling {0}, please wait...", mod.Name), new Action((MethodInvoker)delegate { ModManager.UninstallMod(mod); })); }
private void buttonBuild_Click(object sender, EventArgs e) { SaveFileDialog saveMod = new SaveFileDialog(); saveMod.Filter = "MGSV Mod|*.mgsv"; DialogResult saveResult = saveMod.ShowDialog(); if (saveResult != DialogResult.OK) return; string modPath = textModPath.Text; // delete existing temp directory if (Directory.Exists("_temp")) Directory.Delete("_temp", true); // create new temp fs and QAR file XML Directory.CreateDirectory("_temp\\makebite"); QarFile makeQar = new QarFile(); makeQar.Flags = 3150048; makeQar.Name = "makebite.dat"; makeQar.QarEntries = new List<QarEntry>(); // do files foreach (string modFile in Directory.GetFiles(modPath, "*.*", SearchOption.AllDirectories)) { if (!Hashing.ValidFileExtension(modFile.Substring(modPath.Length))) continue; string subDir = modFile.Substring(0, modFile.LastIndexOf("\\")); // the subdirectory for XML output subDir = subDir.Substring(modPath.Length); if (!Directory.Exists("_temp\\makebite" + subDir)) Directory.CreateDirectory("_temp\\makebite" + subDir); // create file structure File.Copy(modFile, "_temp\\makebite" + modFile.Substring(modPath.Length), true); makeQar.QarEntries.Add(new QarEntry() { FilePath = modFile.Substring(modPath.Length + 1) }); // add to xml } // write xml makeQar.WriteToFile("_temp\\makebite.dat.xml"); // create metadata ModEntry modMetadata = new ModEntry(); modMetadata.Name = textModName.Text; modMetadata.Version = textModVersion.Text; modMetadata.Author = textModAuthor.Text; modMetadata.Website = textModWebsite.Text; modMetadata.Description = textModDescription.Text; modMetadata.ModQarEntries = new List<ModQarEntry>(); modMetadata.ModFpkEntries = new List<ModFpkEntry>(); // create file data foreach (QarEntry newQarEntry in makeQar.QarEntries) { modMetadata.ModQarEntries.Add(new ModQarEntry() { FilePath = Hashing.DenormalizeFilePath(newQarEntry.FilePath), Compressed = newQarEntry.Compressed, Hash = newQarEntry.Hash }); string fileExt = newQarEntry.FilePath.Substring(newQarEntry.FilePath.LastIndexOf(".") + 1).ToLower(); if (fileExt == "fpk" || fileExt == "fpkd") { newQarEntry.Compressed = true; // decompress fpk files and create metadata string fpkDir = "_temp\\makebite\\" + newQarEntry.FilePath.Replace(".", "_"); SnakeBite.GzsTool.GzsTool.Run("_temp\\makebite\\" + newQarEntry.FilePath); foreach (string fpkSubFile in Directory.GetFiles(fpkDir, "*.*", SearchOption.AllDirectories)) { modMetadata.ModFpkEntries.Add(new ModFpkEntry() { FilePath = fpkSubFile.Substring(fpkSubFile.LastIndexOf("\\Assets")).Replace("\\", "/"), FpkFile = "/" + newQarEntry.FilePath.Replace("\\", "/") } ); } Directory.Delete(fpkDir, true); File.Delete("_temp\\makebite\\" + newQarEntry.FilePath + ".xml"); } } modMetadata.SaveToFile("_temp\\makebite\\metadata.xml"); // compress to file FastZip zipper = new FastZip(); zipper.CreateZip(saveMod.FileName, "_temp\\makebite", true, "(.*?)"); Directory.Delete("_temp", true); MessageBox.Show("Done"); }
private void buttonMetaLoad_Click(object sender, EventArgs e) { OpenFileDialog LoadMeta = new OpenFileDialog(); LoadMeta.Filter = "Metadata XML|*.xml"; DialogResult LoadResult = LoadMeta.ShowDialog(); if (LoadResult != DialogResult.OK) return; ModEntry modMetaData = new ModEntry(); modMetaData.ReadFromFile(LoadMeta.FileName); textModName.Text = modMetaData.Name; textModVersion.Text = modMetaData.Version; textModAuthor.Text = modMetaData.Author; textModWebsite.Text = modMetaData.Website; textModDescription.Text = modMetaData.Description.Replace("\n", "\r\n"); }
public static bool UninstallMod(ModEntry mod) { Debug.LogLine(String.Format("[Mod] Uninstall started: {0}", mod.Name), Debug.LogLevel.Basic); CleanupFolders(); // Extract game archive var zeroFiles = GzsLib.ExtractArchive<QarFile>(ZeroPath, "_working"); // List all FPKs in mod List<string> modFpks = new List<string>(); foreach (ModFpkEntry fpkEntry in mod.ModFpkEntries) { if (!modFpks.Contains(fpkEntry.FpkFile)) modFpks.Add(fpkEntry.FpkFile); } var gameData = SettingsManager.GetGameData(); // Extract FPK foreach (string fpk in modFpks) { string fpkName = Path.GetFileName(fpk); string fpkDatPath = zeroFiles.FirstOrDefault(file => Tools.CompareHashes(file, fpk)); if (fpkDatPath == null) continue; var fpkFile = GzsLib.ExtractArchive<FpkFile>(Path.Combine("_working", Tools.ToWinPath(fpkDatPath)), "_modfpk"); // Remove all mod fpk files from fpk foreach (ModFpkEntry fpkEntry in mod.ModFpkEntries) { Debug.LogLine(String.Format("[Mod] Removing {1}\\{0}", Tools.ToWinPath(fpkEntry.FilePath), fpkName), Debug.LogLevel.Debug); fpkFile.RemoveAll(file => Tools.ToQarPath(file) == Tools.ToQarPath(fpkEntry.FilePath)); } var gameFpks = gameData.GameFpkEntries.ToList(); // remove all merged files from fpk foreach (ModFpkEntry gameFpkFile in gameFpks) { if (Tools.ToQarPath(gameFpkFile.FpkFile) == Tools.ToQarPath(fpk) && gameFpkFile.SourceType == FileSource.Merged) { Debug.LogLine(String.Format("[Mod] Removing merged file {0}", gameFpkFile.FilePath)); fpkFile.RemoveAll(entry => entry == gameFpkFile.FilePath); gameData.GameFpkEntries.Remove(gameFpkFile); } } // remove fpk if no files left if (fpkFile.Count == 0) { Debug.LogLine(String.Format("[Mod] {0} is empty, removing", fpkName), Debug.LogLevel.Debug); zeroFiles.RemoveAll(file => Tools.CompareHashes(file, fpk)); gameData.GameQarEntries.RemoveAll(file => Tools.CompareHashes(file.FilePath, fpk)); } else { Debug.LogLine(String.Format("[Mod] Rebuilding {0}", fpk), Debug.LogLevel.Debug); // rebuild fpk from base file var baseData = GzsLib.ReadBaseData(); var oneFiles = baseData.FileList.FindAll(entry => entry.QarFile == "01.dat"); var baseFiles = baseData.FileList.FindAll(entry => entry.QarFile != "01.dat"); // Check for FPKs in 00.dat first GameFile file = oneFiles.FirstOrDefault(entry => entry.FileHash == Tools.NameToHash(fpk)); if (file != null) { // Extract base FPK files GzsLib.ExtractFileByHash<QarFile>(Path.Combine(GameDir, "master\\0\\01.dat"), file.FileHash, "_working\\temp.fpk"); var gameFpk = GzsLib.ExtractArchive<FpkFile>("_working\\temp.fpk", "_gamefpk"); // Add merged base files to game file database var mCount = 0; foreach (var fpkF in gameFpk) { if (!fpkFile.Contains(fpkF)) { gameData.GameFpkEntries.Add(new ModFpkEntry() { FpkFile = fpk, FilePath = fpkF, SourceType = FileSource.Merged, SourceName = file.QarFile }); mCount++; } } Debug.LogLine(String.Format("[Mod] {0} files restored from {1}", mCount, file.QarFile), Debug.LogLevel.Debug); // Copy remaining files over base FPK foreach (string mFile in fpkFile) { string fDir = Path.GetDirectoryName(mFile); if (!Directory.Exists(Path.Combine("_gamefpk", fDir))) Directory.CreateDirectory(Path.Combine("_gamefpk", fDir)); Debug.LogLine(String.Format("[Mod] Merging existing file: {0}", mFile)); File.Copy(Path.Combine("_modfpk", mFile), Path.Combine(Path.Combine("_gamefpk", mFile)), true); if (!gameFpk.Contains(mFile)) gameFpk.Add(mFile); } // Rebuild FPK GzsLib.WriteFpkArchive(Path.Combine("_working", Tools.ToWinPath(fpkDatPath)), "_gamefpk", gameFpk); Directory.Delete("_gamefpk", true); Directory.Delete("_modfpk", true); continue; // don't check base data if it's in 01 } // check base files for FPK file = baseFiles.FirstOrDefault(entry => entry.FileHash == Tools.NameToHash(fpk)); if (file != null) { // Extract base FPK files GzsLib.ExtractFileByHash<QarFile>(Path.Combine(GameDir, "master\\" + file.QarFile), file.FileHash, "_working\\temp.fpk"); var gameFpk = GzsLib.ExtractArchive<FpkFile>("_working\\temp.fpk", "_gamefpk"); // Add merged base files to game file database var mCount = 0; foreach (var fpkF in gameFpk) { if (!fpkFile.Contains(fpkF)) { gameData.GameFpkEntries.Add(new ModFpkEntry() { FpkFile = fpk, FilePath = fpkF, SourceType = FileSource.Merged, SourceName = file.QarFile }); mCount++; } } Debug.LogLine(String.Format("[Mod] {0} files restored from {1}", mCount, file.QarFile), Debug.LogLevel.Debug); // Copy remaining files over base FPK foreach (string mFile in fpkFile) { string fDir = Path.GetDirectoryName(mFile); if (!Directory.Exists(Path.Combine("_gamefpk", fDir))) Directory.CreateDirectory(Path.Combine("_gamefpk", fDir)); Debug.LogLine(String.Format("[Mod] Merging existing file: {0}", mFile)); File.Copy(Path.Combine("_modfpk", mFile), Path.Combine(Path.Combine("_gamefpk", mFile)), true); if (!gameFpk.Contains(mFile)) gameFpk.Add(mFile); } // Rebuild FPK GzsLib.WriteFpkArchive(Path.Combine("_working", Tools.ToWinPath(fpk)), "_gamefpk", gameFpk); Directory.Delete("_gamefpk", true); Directory.Delete("_modfpk", true); } } } SettingsManager.SetGameData(gameData); // Remove all mod files from 01.dat foreach (ModQarEntry qarEntry in mod.ModQarEntries) { string fExt = Path.GetExtension(qarEntry.FilePath); if (!fExt.Contains(".fpk")) { zeroFiles.RemoveAll(file => Tools.CompareHashes(file, qarEntry.FilePath)); } } Debug.LogLine("[Mod] Rebuilding game archive", Debug.LogLevel.Basic); // Rebuild 01.dat GzsLib.WriteQarArchive(ZeroPath, "_working", zeroFiles, 3150048); SettingsManager.UpdateDatHash(); SettingsManager.RemoveMod(mod); CleanupDatabase(); CleanupFolders(); Debug.LogLine("[Mod] Uninstall complete", Debug.LogLevel.Basic); return true; }
public static bool InstallMod(string ModFile) { CleanupFolders(); Debug.LogLine(String.Format("[Mod] Installation started: {0}", ModFile), Debug.LogLevel.Basic); // Extract game archive var zeroFiles = GzsLib.ExtractArchive <QarFile>(ZeroPath, "_working"); // Extract mod data FastZip unzipper = new FastZip(); unzipper.ExtractZip(ModFile, "_extr", "(.*?)"); // Load mod metadata ModEntry metaData = new ModEntry("_extr\\metadata.xml"); // Build a list of FPKs contained in mod List <string> modFpks = new List <string>(); foreach (ModFpkEntry fpkEntry in metaData.ModFpkEntries) { if (!modFpks.Contains(fpkEntry.FpkFile)) { modFpks.Add(fpkEntry.FpkFile); } } List <string> mergeFpks = new List <string>(); List <ModQarEntry> MergeFiles = new List <ModQarEntry>(); Debug.LogLine("[Mod] Checking existing game data", Debug.LogLevel.Basic); // Check for FPKs in 00.dat foreach (string fpk in modFpks) { string datFile = zeroFiles.FirstOrDefault(file => Tools.CompareHashes(file, fpk)); if (datFile != null) { if (mergeFpks.Contains(Tools.ToQarPath(datFile))) { continue; } mergeFpks.Add(fpk); MergeFiles.Add(new ModQarEntry() { FilePath = fpk, SourceType = FileSource.Merged, SourceName = "00.dat" }); } } var gameData = GzsLib.ReadBaseData(); var oneFiles = gameData.FileList.FindAll(entry => entry.QarFile == "01.dat"); var baseFiles = gameData.FileList.FindAll(entry => entry.QarFile != "01.dat"); // Check for FPKs in 01.dat foreach (string fpk in modFpks) { GameFile file = oneFiles.FirstOrDefault(entry => entry.FileHash == Tools.NameToHash(fpk)); if (file != null) { if (mergeFpks.Contains(Tools.ToQarPath(file.FilePath))) { continue; } // Create destination directory string destDirectory = Path.Combine("_working", Path.GetDirectoryName(Tools.ToWinPath(file.FilePath))); if (!Directory.Exists(destDirectory)) { Directory.CreateDirectory(destDirectory); } // Extract file into dat directory var ex = GzsLib.ExtractFileByHash <QarFile>(Path.Combine(GameDir, "master\\0\\01.dat"), file.FileHash, Path.Combine("_working", Tools.ToWinPath(file.FilePath))); mergeFpks.Add(Tools.ToQarPath(file.FilePath)); MergeFiles.Add(new ModQarEntry() { FilePath = file.FilePath, SourceType = FileSource.Merged, SourceName = "01.dat" }); if (zeroFiles.FirstOrDefault(datFile => Tools.CompareHashes(datFile, file.FilePath)) == null) { zeroFiles.Add(Tools.ToWinPath(file.FilePath)); } } } // Check for FPKs in base data foreach (string fpk in modFpks) { GameFile file = baseFiles.FirstOrDefault(entry => entry.FileHash == Tools.NameToHash(fpk)); if (file != null) { if (mergeFpks.Contains(Tools.ToQarPath(file.FilePath))) { continue; } // Create destination directory string destDirectory = Path.Combine("_working", Path.GetDirectoryName(Tools.ToWinPath(file.FilePath))); if (!Directory.Exists(destDirectory)) { Directory.CreateDirectory(destDirectory); } // Extract file into dat directory var ex = GzsLib.ExtractFileByHash <QarFile>(Path.Combine(GameDir, "master\\" + file.QarFile), file.FileHash, Path.Combine("_working", Tools.ToWinPath(file.FilePath))); mergeFpks.Add(Tools.ToQarPath(file.FilePath)); MergeFiles.Add(new ModQarEntry() { FilePath = file.FilePath, SourceType = FileSource.Merged, SourceName = file.QarFile }); if (zeroFiles.FirstOrDefault(datFile => Tools.CompareHashes(datFile, file.FilePath)) == null) { zeroFiles.Add(Tools.ToWinPath(file.FilePath)); } } } Debug.LogLine(String.Format("[Mod] Merging {0} FPK files", MergeFiles.Count), Debug.LogLevel.Basic); var g = SettingsManager.GetGameData(); // Merge FPK files foreach (ModQarEntry gf in MergeFiles) { Debug.LogLine(String.Format("[Mod] Starting merge: {0} ({1})", gf.FilePath, gf.SourceName), Debug.LogLevel.Debug); // Extract game FPK string fpkDatPath = zeroFiles.FirstOrDefault(file => Tools.CompareHashes(file, gf.FilePath)); string fpkPath = Path.Combine("_working", Tools.ToWinPath(fpkDatPath)); var gameFpk = GzsLib.ExtractArchive <FpkFile>(fpkPath, "_gamefpk"); // Extract mod FPK var exFpk = GzsLib.ExtractArchive <FpkFile>(Path.Combine("_extr", Tools.ToWinPath(gf.FilePath)), "_modfpk"); // Add file to gamedata info var q = g.GameQarEntries.FirstOrDefault(entry => entry.FilePath == gf.FilePath); if (q == null) { g.GameQarEntries.Add(new ModQarEntry() { FilePath = Tools.ToQarPath(gf.FilePath), SourceType = gf.SourceType, SourceName = gf.SourceName, Hash = Tools.NameToHash(gf.FilePath) }); } foreach (string f in gameFpk) { var c = exFpk.FirstOrDefault(entry => Tools.CompareHashes(entry, f)); if (c == null) { if (g.GameFpkEntries.FirstOrDefault(entry => Tools.CompareHashes(entry.FpkFile, gf.FilePath) && Tools.CompareNames(entry.FilePath, f)) == null) { g.GameFpkEntries.Add(new ModFpkEntry() { FpkFile = Tools.ToQarPath(gf.FilePath), FilePath = f, SourceType = gf.SourceType, SourceName = gf.SourceName }); } } } // Merge contents foreach (string fileName in exFpk) { string fileDir = (Path.Combine("_gamefpk", Path.GetDirectoryName(fileName))); string sourceFile = Path.Combine("_modfpk", fileName); string destFile = Path.Combine("_gamefpk", fileName); Debug.LogLine(String.Format("[Mod] Copying file: {0}", fileName), Debug.LogLevel.All); if (!Directory.Exists(fileDir)) { Directory.CreateDirectory(fileDir); } File.Copy(sourceFile, destFile, true); if (!gameFpk.Contains(fileName)) { gameFpk.Add(Tools.ToQarPath(fileName)); } } // Rebuild game FPK GzsLib.WriteFpkArchive(fpkPath, "_gamefpk", gameFpk); if (!zeroFiles.Contains(Tools.ToWinPath(gf.FilePath))) { zeroFiles.Add(Tools.ToWinPath(gf.FilePath)); } Directory.Delete("_modfpk", true); Directory.Delete("_gamefpk", true); Debug.LogLine(String.Format("[Mod] Merge complete"), Debug.LogLevel.Debug); } SettingsManager.SetGameData(g); Debug.LogLine("[Mod] Copying remaining mod files", Debug.LogLevel.Basic); // Copy files for 01.dat, ignoring merged FPKs foreach (ModQarEntry modEntry in metaData.ModQarEntries) { if (!zeroFiles.Contains(Tools.ToWinPath(modEntry.FilePath))) { zeroFiles.Add(Tools.ToWinPath(modEntry.FilePath)); } if (modEntry.FilePath.Contains(".fpk")) { if (mergeFpks.Count(fpk => Tools.CompareHashes(fpk, modEntry.FilePath)) > 0) { continue; } } string sourceFile = Path.Combine("_extr", Tools.ToWinPath(modEntry.FilePath)); string destFile = Path.Combine("_working", Tools.ToWinPath(modEntry.FilePath)); string destDir = Path.GetDirectoryName(destFile); Debug.LogLine(String.Format("[Mod] Copying file: {0}", modEntry.FilePath), Debug.LogLevel.All); if (!Directory.Exists(destDir)) { Directory.CreateDirectory(destDir); } File.Copy(sourceFile, destFile, true); } // Rebuild 01.dat Debug.LogLine("[Mod] Rebuilding game archive", Debug.LogLevel.Basic); GzsLib.WriteQarArchive(ZeroPath, "_working", zeroFiles, 3150048); SettingsManager.UpdateDatHash(); SettingsManager.AddMod(metaData); Debug.LogLine("[Mod] Running database cleanup", Debug.LogLevel.Debug); CleanupDatabase(); CleanupFolders(); Debug.LogLine("[Mod] Installation finished", Debug.LogLevel.Basic); return(true); }
private void formMain_Load(object sender, EventArgs e) { comboForVersion.SelectedIndex = comboForVersion.Items.Count - 1; string modPath = Properties.Settings.Default.LastModDir; if (Directory.Exists(modPath)) { if(File.Exists(modPath + "\\metadata.xml")) { ModEntry modMetaData = new ModEntry(); modMetaData.ReadFromFile(modPath + "\\metadata.xml"); textModName.Text = modMetaData.Name; textModVersion.Text = modMetaData.Version; textModAuthor.Text = modMetaData.Author; textModWebsite.Text = modMetaData.Website; textModDescription.Text = modMetaData.Description.Replace("\n", "\r\n"); } textModPath.Text = modPath; foreach (string modFile in Directory.GetFiles(modPath, "*.*", SearchOption.AllDirectories)) { string filePath = modFile.Substring(modPath.Length).Replace("\\", "/"); if (Hashing.ValidFileExtension(filePath) && filePath != "/metadata.xml") listModFiles.Items.Add(filePath); } } else { Properties.Settings.Default.LastModDir = String.Empty; Properties.Settings.Default.Save(); } }
private void ProcessUninstallMod(ModEntry mod) { showProgressWindow(String.Format("Please wait while {0} is uninstalled...", mod.Name)); // Remove from mod database objSettings.ModEntries.Remove(mod); objSettings.SaveSettings(); // Uninstall mod ModManager.UninstallMod(mod); // Update installed mod list RefreshInstalledMods(true); hideProgressWindow(); }
private void ProcessInstallMod(string ModFile, bool ignoreConflicts = false) { // extract metadata and load FastZip unzipper = new FastZip(); unzipper.ExtractZip(ModFile, ".", "metadata.xml"); ModEntry modMetadata = new ModEntry(); modMetadata.ReadFromFile("metadata.xml"); File.Delete("metadata.xml"); // delete temp metadata if (!checkConflicts.Checked && !ignoreConflicts) { // check version conflicts int SBVersion = ModManager.GetSBVersion(); int MGSVersion = ModManager.GetMGSVersion(); int modSBVersion = Convert.ToInt32(modMetadata.SBVersion); int modMGSVersion = Convert.ToInt32(modMetadata.MGSVersion); // Check if mod requires SB update if (modSBVersion > SBVersion) { MessageBox.Show(String.Format("{0} requires a newer version of SnakeBite. Please follow the link on the Settings page to get the latest version.", modMetadata.Name), "Update required", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } // Check MGS version compatibility if (MGSVersion != modMGSVersion && modMGSVersion != 0) { if (MGSVersion > modMGSVersion) MessageBox.Show(String.Format("{0} requires MGSV version {1}, but your installation is version {2}. Please update {0} and try again.", modMetadata.Name, modMGSVersion, MGSVersion), "Update required", MessageBoxButtons.OK, MessageBoxIcon.Error); if (MGSVersion < modMGSVersion) MessageBox.Show(String.Format("{0} requires MGSV version {1}, but your installation is version {2}. Please update MGSV and try again.", modMetadata.Name, modMGSVersion, MGSVersion), "Update required", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } // search installed mods for conflicts List<string> conflictingMods = new List<string>(); foreach (ModEntry modEntry in objSettings.ModEntries) // iterate through installed mods { foreach (ModQarEntry qarEntry in modMetadata.ModQarEntries) // iterate qar files from new mod { ModQarEntry conflicts = modEntry.ModQarEntries.FirstOrDefault(entry => entry.FilePath == qarEntry.FilePath); if (conflicts != null) { conflictingMods.Add(modEntry.Name); break; } } foreach (ModFpkEntry fpkEntry in modMetadata.ModFpkEntries) // iterate fpk files from new mod { ModFpkEntry conflicts = modEntry.ModFpkEntries.FirstOrDefault(entry => entry.FpkFile == fpkEntry.FpkFile && entry.FilePath == fpkEntry.FilePath); if (conflicts != null) { if (!conflictingMods.Contains(modEntry.Name)) { conflictingMods.Add(modEntry.Name); break; } } } } // if the mod conflicts, display message if (conflictingMods.Count > 0) { string msgboxtext = "The selected mod conflicts with these mods:\n"; foreach (string Conflict in conflictingMods) { msgboxtext += Conflict + "\n"; } msgboxtext += "\nPlease uninstall the mods above and try again."; MessageBox.Show(msgboxtext, "Installation Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } bool sysConflict = false; // check for system file conflicts foreach (ModQarEntry gameQarFile in objSettings.GameData.GameQarEntries) { if (modMetadata.ModQarEntries.Count(entry => entry.FilePath == gameQarFile.FilePath) > 0) sysConflict = true; } foreach (ModFpkEntry gameFpkFile in objSettings.GameData.GameFpkEntries) { if (modMetadata.ModFpkEntries.Count(entry => entry.FilePath == gameFpkFile.FilePath && entry.FpkFile == gameFpkFile.FpkFile) > 0) sysConflict = true; } if (sysConflict) { MessageBox.Show("The selected mod conflicts with existing MGSV system files.", "SnakeBite", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } } DialogResult confirmInstall = MessageBox.Show(String.Format("You are about to install {0}, continue?", modMetadata.Name), "SnakeBite", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (confirmInstall == DialogResult.No) return; showProgressWindow(String.Format("Installing {0}, please wait...", modMetadata.Name)); // Install mod to game database objSettings.ModEntries.Add(modMetadata); objSettings.SaveSettings(); // Install mod to 01.dat ModManager.InstallMod(ModFile); RefreshInstalledMods(); listInstalledMods.SelectedIndex = listInstalledMods.Items.Count - 1; hideProgressWindow(); }
private void buttonInstallMod_Click(object sender, EventArgs e) { // Show open file dialog for mod file OpenFileDialog openModFile = new OpenFileDialog(); openModFile.Filter = "MGSV Mod Files|*.mgsv|All Files|*.*"; DialogResult ofdResult = openModFile.ShowDialog(); if (ofdResult != DialogResult.OK) return; // extract metadata and load FastZip unzipper = new FastZip(); unzipper.ExtractZip(openModFile.FileName, ".", "metadata.xml"); ModEntry modMetadata = new ModEntry(); modMetadata.ReadFromFile("metadata.xml"); File.Delete("metadata.xml"); // delete temp metadata if(!checkConflicts.Checked) { // search installed mods for conflicts List<string> conflictingMods = new List<string>(); foreach (ModEntry modEntry in objSettings.ModEntries) // iterate through installed mods { foreach (ModQarEntry qarEntry in modMetadata.ModQarEntries) // iterate qar files from new mod { ModQarEntry conflicts = modEntry.ModQarEntries.FirstOrDefault(entry => entry.FilePath == qarEntry.FilePath); if (conflicts != null) { conflictingMods.Add(modEntry.Name); break; } } foreach (ModFpkEntry fpkEntry in modMetadata.ModFpkEntries) // iterate fpk files from new mod { ModFpkEntry conflicts = modEntry.ModFpkEntries.FirstOrDefault(entry => entry.FpkFile == fpkEntry.FpkFile && entry.FilePath == fpkEntry.FilePath); if (conflicts != null) { if (!conflictingMods.Contains(modEntry.Name)) { conflictingMods.Add(modEntry.Name); break; } } } } // if the mod conflicts, display message if (conflictingMods.Count > 0) { string msgboxtext = "The selected mod conflicts with these mods:\n"; foreach (string Conflict in conflictingMods) { msgboxtext += Conflict + "\n"; } msgboxtext += "\nPlease uninstall the mods above and try again."; MessageBox.Show(msgboxtext, "Installation Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } bool sysConflict = false; // check for system file conflicts foreach (ModQarEntry gameQarFile in objSettings.GameData.GameQarEntries) { if (modMetadata.ModQarEntries.Count(entry => entry.FilePath == gameQarFile.FilePath) > 0) sysConflict = true; } foreach (ModFpkEntry gameFpkFile in objSettings.GameData.GameFpkEntries) { if (modMetadata.ModFpkEntries.Count(entry => entry.FilePath == gameFpkFile.FilePath && entry.FpkFile == gameFpkFile.FpkFile) > 0) sysConflict = true; } if (sysConflict) { MessageBox.Show("The selected mod conflicts with existing MGSV system files.", "SnakeBite", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } } DialogResult confirmInstall = MessageBox.Show(String.Format("You are about to install {0}, continue?", modMetadata.Name), "SnakeBite", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (confirmInstall == DialogResult.No) return; showProgressWindow(String.Format("Installing {0}, please wait...", modMetadata.Name)); // Install mod to game database objSettings.ModEntries.Add(modMetadata); objSettings.SaveSettings(); // Install mod to 01.dat ModManager.InstallMod(openModFile.FileName); LoadInstalledMods(); listInstalledMods.SelectedIndex = listInstalledMods.Items.Count - 1; hideProgressWindow(); }
public static void BuildArchive(string SourceDir, ModEntry metaData, string OutputFile) { string buildDir = Directory.GetCurrentDirectory() + "\\build"; if (Directory.Exists(buildDir)) Directory.Delete(buildDir, true); Directory.CreateDirectory("_build"); // check for FPKs that must be built and build metaData.ModFpkEntries = new List<ModFpkEntry>(); List<string> builtFpks = new List<string>(); foreach (string FpkDir in ListFpkFolders(SourceDir)) { foreach (ModFpkEntry fpkEntry in BuildFpk(FpkDir, SourceDir)) { metaData.ModFpkEntries.Add(fpkEntry); if (!builtFpks.Contains(fpkEntry.FpkFile)) builtFpks.Add(fpkEntry.FpkFile); } } // check for other FPKs and build fpkentry data foreach (string SourceFile in Directory.GetFiles(SourceDir, "*.fpk*", SearchOption.AllDirectories)) { string FileName = Tools.ToQarPath(SourceFile.Substring(SourceDir.Length)); if (!builtFpks.Contains(FileName)) { // unpack FPK and build FPK list foreach (string file in GzsLib.ListArchiveContents<FpkFile>(SourceFile)) { string fpkDir = Tools.ToWinPath(FileName.Replace(".fpk", "_fpk")); string fpkFullDir = Path.Combine(SourceDir, fpkDir); if (!Directory.Exists(fpkFullDir)) { GzsLib.ExtractArchive<FpkFile>(SourceFile, fpkFullDir); } metaData.ModFpkEntries.Add(new ModFpkEntry() { FilePath = file, FpkFile = FileName, ContentHash = Tools.GetMd5Hash(Path.Combine(SourceDir, fpkDir, Tools.ToWinPath(file))) }); } } } // build QAR entries metaData.ModQarEntries = new List<ModQarEntry>(); foreach (string qarFile in ListQarFiles(SourceDir)) { string subDir = qarFile.Substring(0, qarFile.LastIndexOf("\\")).Substring(SourceDir.Length).TrimStart('\\'); // the subdirectory for XML output string qarFilePath = Tools.ToQarPath(qarFile.Substring(SourceDir.Length)); if (!Directory.Exists(Path.Combine("_build", subDir))) Directory.CreateDirectory(Path.Combine("_build", subDir)); // create file structure File.Copy(qarFile, Path.Combine("_build", Tools.ToWinPath(qarFilePath)), true); ulong hash = Tools.NameToHash(qarFilePath); metaData.ModQarEntries.Add(new ModQarEntry() { FilePath = qarFilePath, Compressed = qarFile.Substring(qarFile.LastIndexOf(".") + 1).Contains("fpk") ? true : false, ContentHash = Tools.GetMd5Hash(qarFile), Hash = hash }); } metaData.SBVersion.Version = "0.8.0.0"; metaData.SaveToFile("_build\\metadata.xml"); // build archive FastZip zipper = new FastZip(); zipper.CreateZip(OutputFile, "_build", true, "(.*?)"); Directory.Delete("_build", true); }
public void ProcessUninstallMod(ModEntry mod) { ProgressWindow.Show("Uninstalling Mod", String.Format("Uninstalling {0}, please wait...", mod.Name), new Action((MethodInvoker) delegate { ModManager.UninstallMod(mod); })); }
public static bool UninstallMod(ModEntry mod) { Debug.LogLine(String.Format("[Mod] Uninstall started: {0}", mod.Name), Debug.LogLevel.Basic); CleanupFolders(); // Extract game archive var zeroFiles = GzsLib.ExtractArchive <QarFile>(ZeroPath, "_working"); // List all FPKs in mod List <string> modFpks = new List <string>(); foreach (ModFpkEntry fpkEntry in mod.ModFpkEntries) { if (!modFpks.Contains(fpkEntry.FpkFile)) { modFpks.Add(fpkEntry.FpkFile); } } var gameData = SettingsManager.GetGameData(); // Extract FPK foreach (string fpk in modFpks) { string fpkName = Path.GetFileName(fpk); string fpkDatPath = zeroFiles.FirstOrDefault(file => Tools.CompareHashes(file, fpk)); if (fpkDatPath == null) { continue; } var fpkFile = GzsLib.ExtractArchive <FpkFile>(Path.Combine("_working", Tools.ToWinPath(fpkDatPath)), "_modfpk"); // Remove all mod fpk files from fpk foreach (ModFpkEntry fpkEntry in mod.ModFpkEntries) { Debug.LogLine(String.Format("[Mod] Removing {1}\\{0}", Tools.ToWinPath(fpkEntry.FilePath), fpkName), Debug.LogLevel.Debug); fpkFile.RemoveAll(file => Tools.ToQarPath(file) == Tools.ToQarPath(fpkEntry.FilePath)); } var gameFpks = gameData.GameFpkEntries.ToList(); // remove all merged files from fpk foreach (ModFpkEntry gameFpkFile in gameFpks) { if (Tools.ToQarPath(gameFpkFile.FpkFile) == Tools.ToQarPath(fpk) && gameFpkFile.SourceType == FileSource.Merged) { Debug.LogLine(String.Format("[Mod] Removing merged file {0}", gameFpkFile.FilePath)); fpkFile.RemoveAll(entry => entry == gameFpkFile.FilePath); gameData.GameFpkEntries.Remove(gameFpkFile); } } // remove fpk if no files left if (fpkFile.Count == 0) { Debug.LogLine(String.Format("[Mod] {0} is empty, removing", fpkName), Debug.LogLevel.Debug); zeroFiles.RemoveAll(file => Tools.CompareHashes(file, fpk)); gameData.GameQarEntries.RemoveAll(file => Tools.CompareHashes(file.FilePath, fpk)); } else { Debug.LogLine(String.Format("[Mod] Rebuilding {0}", fpk), Debug.LogLevel.Debug); // rebuild fpk from base file var baseData = GzsLib.ReadBaseData(); var oneFiles = baseData.FileList.FindAll(entry => entry.QarFile == "01.dat"); var baseFiles = baseData.FileList.FindAll(entry => entry.QarFile != "01.dat"); // Check for FPKs in 00.dat first GameFile file = oneFiles.FirstOrDefault(entry => entry.FileHash == Tools.NameToHash(fpk)); if (file != null) { // Extract base FPK files GzsLib.ExtractFileByHash <QarFile>(Path.Combine(GameDir, "master\\0\\01.dat"), file.FileHash, "_working\\temp.fpk"); var gameFpk = GzsLib.ExtractArchive <FpkFile>("_working\\temp.fpk", "_gamefpk"); // Add merged base files to game file database var mCount = 0; foreach (var fpkF in gameFpk) { if (!fpkFile.Contains(fpkF)) { gameData.GameFpkEntries.Add(new ModFpkEntry() { FpkFile = fpk, FilePath = fpkF, SourceType = FileSource.Merged, SourceName = file.QarFile }); mCount++; } } Debug.LogLine(String.Format("[Mod] {0} files restored from {1}", mCount, file.QarFile), Debug.LogLevel.Debug); // Copy remaining files over base FPK foreach (string mFile in fpkFile) { string fDir = Path.GetDirectoryName(mFile); if (!Directory.Exists(Path.Combine("_gamefpk", fDir))) { Directory.CreateDirectory(Path.Combine("_gamefpk", fDir)); } Debug.LogLine(String.Format("[Mod] Merging existing file: {0}", mFile)); File.Copy(Path.Combine("_modfpk", mFile), Path.Combine(Path.Combine("_gamefpk", mFile)), true); if (!gameFpk.Contains(mFile)) { gameFpk.Add(mFile); } } // Rebuild FPK GzsLib.WriteFpkArchive(Path.Combine("_working", Tools.ToWinPath(fpkDatPath)), "_gamefpk", gameFpk); Directory.Delete("_gamefpk", true); Directory.Delete("_modfpk", true); continue; // don't check base data if it's in 01 } // check base files for FPK file = baseFiles.FirstOrDefault(entry => entry.FileHash == Tools.NameToHash(fpk)); if (file != null) { // Extract base FPK files GzsLib.ExtractFileByHash <QarFile>(Path.Combine(GameDir, "master\\" + file.QarFile), file.FileHash, "_working\\temp.fpk"); var gameFpk = GzsLib.ExtractArchive <FpkFile>("_working\\temp.fpk", "_gamefpk"); // Add merged base files to game file database var mCount = 0; foreach (var fpkF in gameFpk) { if (!fpkFile.Contains(fpkF)) { gameData.GameFpkEntries.Add(new ModFpkEntry() { FpkFile = fpk, FilePath = fpkF, SourceType = FileSource.Merged, SourceName = file.QarFile }); mCount++; } } Debug.LogLine(String.Format("[Mod] {0} files restored from {1}", mCount, file.QarFile), Debug.LogLevel.Debug); // Copy remaining files over base FPK foreach (string mFile in fpkFile) { string fDir = Path.GetDirectoryName(mFile); if (!Directory.Exists(Path.Combine("_gamefpk", fDir))) { Directory.CreateDirectory(Path.Combine("_gamefpk", fDir)); } Debug.LogLine(String.Format("[Mod] Merging existing file: {0}", mFile)); File.Copy(Path.Combine("_modfpk", mFile), Path.Combine(Path.Combine("_gamefpk", mFile)), true); if (!gameFpk.Contains(mFile)) { gameFpk.Add(mFile); } } // Rebuild FPK GzsLib.WriteFpkArchive(Path.Combine("_working", Tools.ToWinPath(fpk)), "_gamefpk", gameFpk); Directory.Delete("_gamefpk", true); Directory.Delete("_modfpk", true); } } } SettingsManager.SetGameData(gameData); // Remove all mod files from 01.dat foreach (ModQarEntry qarEntry in mod.ModQarEntries) { string fExt = Path.GetExtension(qarEntry.FilePath); if (!fExt.Contains(".fpk")) { zeroFiles.RemoveAll(file => Tools.CompareHashes(file, qarEntry.FilePath)); } } Debug.LogLine("[Mod] Rebuilding game archive", Debug.LogLevel.Basic); // Rebuild 01.dat GzsLib.WriteQarArchive(ZeroPath, "_working", zeroFiles, 3150048); SettingsManager.UpdateDatHash(); SettingsManager.RemoveMod(mod); CleanupDatabase(); CleanupFolders(); Debug.LogLine("[Mod] Uninstall complete", Debug.LogLevel.Basic); return(true); }
private void DoBuild(string BuildFile) { ModEntry modMetaData = new ModEntry(); modMetaData.Name = textModName.Text; modMetaData.Author = textModAuthor.Text; modMetaData.Version = textModVersion.Text; modMetaData.MGSVersion.Version = comboForVersion.Text; modMetaData.Website = textModWebsite.Text; modMetaData.Description = textModDescription.Text; modMetaData.SaveToFile(textModPath.Text + "\\metadata.xml"); Build.BuildArchive(textModPath.Text, modMetaData, BuildFile); }
private void PopulateBoxes(string DataPath) { // unpack existing fpks foreach (string fpkFile in Directory.GetFiles(DataPath, "*.fpk*", SearchOption.AllDirectories)) { string fpkDir = Path.Combine(Path.GetDirectoryName(fpkFile), Path.GetFileName(fpkFile).Replace(".", "_")); if (!Directory.Exists(fpkDir)) { //extract fpk GzsLib.ExtractArchive<FpkFile>(fpkFile, fpkDir); } } foreach (string modFile in Directory.GetFiles(DataPath, "*.*", SearchOption.AllDirectories)) { string filePath = modFile.Substring(DataPath.Length).Replace("\\", "/"); if (Tools.IsValidFile(filePath) && filePath != "/metadata.xml") listModFiles.Items.Add(filePath); } if (File.Exists(Path.Combine(DataPath, "metadata.xml"))) { ModEntry modMetaData = new ModEntry(); modMetaData.ReadFromFile(Path.Combine(DataPath, "metadata.xml")); textModName.Text = modMetaData.Name; textModVersion.Text = modMetaData.Version; textModAuthor.Text = modMetaData.Author; textModWebsite.Text = modMetaData.Website; textModDescription.Text = modMetaData.Description.Replace("\n", "\r\n"); foreach (string li in comboForVersion.Items) { if (modMetaData.MGSVersion.AsString() == li) { comboForVersion.SelectedIndex = comboForVersion.Items.IndexOf(li); break; } } } if (File.Exists(DataPath + "\\readme.txt")) { StreamReader s = new StreamReader(DataPath + "\\readme.txt"); string readme = s.ReadToEnd(); textModDescription.Text = readme; } }
public static bool UninstallMod(ModEntry mod) { // extract 01.dat if (!ModManager.ValidInstallPath) return false; // no valid install specified if (!File.Exists(GameArchivePath)) return false; ExtractGameArchive(); // load xml data QarFile datXml = new QarFile(); datXml.LoadFromFile(GameArchiveXmlPath); // check for fpks List<string> modFpks = new List<string>(); foreach (ModFpkEntry modFpkFile in mod.ModFpkEntries) { if (datXml.QarEntries.Count(entry => entry.FilePath == modFpkFile.FpkFile) > 0 && !modFpks.Contains(modFpkFile.FpkFile)) { modFpks.Add(modFpkFile.FpkFile); } } // do the fpks thing // unpack fpk foreach (string fpkFile in modFpks) { // check if fpk file exists in game data if (File.Exists(GameArchiveDir + fpkFile.Replace("/", "\\"))) { // extract fpk GzsTool.GzsTool.Run(GameArchiveDir + Tools.ToWinPath(fpkFile)); string fpkDir = GameArchiveDir + Tools.ToWinPath(fpkFile.Replace(".", "_")); FpkFile fpkXml = new FpkFile(); fpkXml.LoadFromFile(GameArchiveDir + fpkFile + ".xml"); // check if any files left in fpk List<FpkEntry> fpkFiles = fpkXml.FpkEntries.ToList(); foreach (FpkEntry fpkSubFile in fpkXml.FpkEntries) { fpkFiles.RemoveAll(entry => entry.FilePath == fpkSubFile.FilePath); } // if not, remove it if (fpkFiles.Count == 0) { // delete fpk from dat XML datXml.QarEntries.RemoveAll(entry => entry.FilePath == fpkFile); } } } // remove mod files from xml foreach (ModQarEntry modQEntry in mod.ModQarEntries) { // delete files, fpks that were de-merged will be ignored if (!modFpks.Contains(modQEntry.FilePath)) { datXml.QarEntries.RemoveAll(entry => entry.FilePath == modQEntry.FilePath); } } // rebuild 01.dat datXml.WriteToFile(GameArchiveXmlPath); GzsTool.GzsTool.Run(GameArchiveXmlPath); DeleteGameArchive(); UpdateDatHash(); return true; }
public static bool UninstallMods(CheckedListBox.CheckedIndexCollection modIndices, bool skipCleanup = false) // Uninstalls mods based on their indices in the list { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); Debug.LogLine("[Uninstall] Start", Debug.LogLevel.Basic); // initial cleanup ModManager.ClearBuildFiles(ZeroPath, OnePath, SnakeBiteSettings, SavePresetPath); ModManager.ClearSBGameDir(); ModManager.CleanupFolders(); // backup preset build if (Properties.Settings.Default.AutosaveRevertPreset == true) { PresetManager.SavePreset(SavePresetPath + build_ext); } else { Debug.LogLine("[Uninstall] Skipping RevertChanges.MGSVPreset Save", Debug.LogLevel.Basic); } GzsLib.LoadDictionaries(); File.Copy(SnakeBiteSettings, SnakeBiteSettings + build_ext, true); List <ModEntry> mods = SBBuildManager.GetInstalledMods(); List <ModEntry> selectedMods = new List <ModEntry>(); foreach (int index in modIndices) { ModEntry mod = mods[index]; selectedMods.Add(mod); } List <string> zeroFiles = new List <string>(); bool hasQarZero = ModManager.hasQarZeroFiles(selectedMods); if (hasQarZero) { // if necessary, extracts 00.dat and creates a list of filenames, which is pruned throughout the uninstall process and repacked at the end. zeroFiles = GzsLib.ExtractArchive <QarFile>(ZeroPath, "_working0"); zeroFiles.RemoveAll(file => file.EndsWith("_unknown")); } List <string> oneFiles = null; bool hasFtexs = ModManager.foundLooseFtexs(selectedMods); if (hasFtexs) { // if necessary, extracts 01.dat and creates a list of filenames similar to zeroFiles. only textures are pruned from the list. oneFiles = GzsLib.ExtractArchive <QarFile>(OnePath, "_working1"); oneFiles.RemoveAll(file => file.EndsWith("_unknown")); } //end of qar extraction GameData gameData = SBBuildManager.GetGameData(); ModManager.ValidateGameData(ref gameData, ref zeroFiles); Debug.LogLine("[Uninstall] Building gameFiles lists", Debug.LogLevel.Basic); var baseGameFiles = GzsLib.ReadBaseData(); try { ModManager.PrepGameDirFiles(); // begin uninstall UninstallMods(selectedMods, ref zeroFiles, ref oneFiles); if (hasQarZero) { zeroFiles.Sort(); GzsLib.WriteQarArchive(ZeroPath + build_ext, "_working0", zeroFiles, GzsLib.zeroFlags); } if (hasFtexs) { oneFiles.Sort(); GzsLib.WriteQarArchive(OnePath + build_ext, "_working1", oneFiles, GzsLib.oneFlags); } // end of qar rebuild // overwrite old mod data ModManager.PromoteGameDirFiles(); ModManager.PromoteBuildFiles(ZeroPath, OnePath, SnakeBiteSettings, SavePresetPath); if (!skipCleanup) { ModManager.CleanupFolders(); ModManager.ClearSBGameDir(); } Debug.LogLine("[Uninstall] Uninstall complete", Debug.LogLevel.Basic); stopwatch.Stop(); Debug.LogLine($"[Uninstall] Uninstall took {stopwatch.ElapsedMilliseconds} ms", Debug.LogLevel.Basic); return(true); } catch (Exception e) { Debug.LogLine("[Uninstall] Exception: " + e, Debug.LogLevel.Basic); stopwatch.Stop(); Debug.LogLine($"[Uninstall] Uninstall failed at {stopwatch.ElapsedMilliseconds} ms", Debug.LogLevel.Basic); MessageBox.Show("An error has occurred during the uninstallation process and SnakeBite could not uninstall the selected mod(s).\nException: " + e); // clean up failed files ModManager.ClearBuildFiles(ZeroPath, OnePath, SnakeBiteSettings, SavePresetPath); ModManager.CleanupFolders(); bool restoreRetry = false; do { try { ModManager.RestoreBackupGameDir(SBBuildManager); } catch (Exception f) { Debug.LogLine("[Uninstall] Exception: " + f, Debug.LogLevel.Basic); restoreRetry = DialogResult.Retry == MessageBox.Show("SnakeBite could not restore Game Directory mod files due to the following exception: {f} \nWould you like to retry?", "Exception Occurred", MessageBoxButtons.RetryCancel, MessageBoxIcon.Error); } } while (restoreRetry); ModManager.ClearSBGameDir(); return(false); } }//UninstallMod batch
private static void Main(string[] args) { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); SettingsManager manager = new SettingsManager(ModManager.GameDir); manager.DisableConflictCheck = false; if (Properties.Settings.Default.LastSBVersion == null || new Version(Properties.Settings.Default.LastSBVersion) < ModManager.GetSBVersion()) { Properties.Settings.Default.Upgrade(); } Properties.Settings.Default.LastSBVersion = ModManager.GetSBVersion().ToString(); Properties.Settings.Default.Save(); Debug.Clear(); Debug.LogLine(String.Format( "SnakeBite {0}\n" + "{1}\n" + "-------------------------", ModManager.GetSBVersion(), Environment.OSVersion.VersionString)); // Delete old settings file if (File.Exists(ModManager.GameDir + "\\sbmods.xml")) { Debug.LogLine("Settings v0.7 or less detected, removing"); File.Delete(ModManager.GameDir + "\\sbmods.xml"); MessageBox.Show("Due to fundamental changes from version 0.8 onwards, your settings have been reset. Please re-verify or restore the game files and run the setup wizard before continuing.", "Version Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } bool showSetupWizard = false; if (!manager.SettingsExist() || !manager.ValidInstallPath) { showSetupWizard = true; } // Show wizard on first run, if folder is invalid or settings out of date while (showSetupWizard) { // show setup wizard Debug.LogLine("Showing setup wizard"); SetupWizard.SetupWizard setupWizard = new SetupWizard.SetupWizard(); var wizResult = setupWizard.ShowDialog(); if (wizResult == DialogResult.Cancel) { return; } if (wizResult == DialogResult.OK) { showSetupWizard = false; } } string InitLog = String.Format( "MGS Install Folder: {0}\n" + "MGS Version: {1}\n" + "-------------------------", Properties.Settings.Default.InstallPath, ModManager.GetMGSVersion()); Debug.LogLine(InitLog, Debug.LogLevel.Basic); // Process Command Line args // TODO: test all command line args // Uninstall SnakeBite if (args.Length == 1) { if (args[0] == "-completeuninstall") { Debug.LogLine("Complete uninstall"); // Restore backup and remove settings manager.DeleteSettings(); BackupManager.RestoreOriginals(); return; } } // Parse command line arguments bool doCmdLine = false; // Process command line args? bool closeApp = false; // Close app after? bool install = false; // Install = true, uninstall = false bool resetDatHash = false; // Rehash dat file bool skipCleanup = true; // Skip CleanupDatabase string installFile = String.Empty; if (args.Length > 0) { foreach (string arg in args) { switch (arg.ToLower()) { case "-i": install = true; break; case "-u": install = false; break; case "-d": resetDatHash = true; break; case "-x": closeApp = true; break; case "-s": skipCleanup = true; break; default: installFile = arg; doCmdLine = true; break; } } } // Update dat hash in settings if (resetDatHash) { Debug.LogLine("Resetting dat hash"); manager.UpdateDatHash(); } if (ModManager.GetMGSVersion() > new Version(1, 0, 13, 0)) { var contSB = MessageBox.Show("Due to a recent game update, this version of SnakeBite is outdated, and some features will not function properly.\n\nIt is highly recommended that you do not continue, and update to the latest version of Snakebite when it becomes available.\n\nWould you still like to continue? ", "Game Version Update", MessageBoxButtons.YesNo, MessageBoxIcon.Warning); if (contSB == DialogResult.No) { return; } } var checkDat = manager.ValidateDatHash(); if (!checkDat || manager.IsVanilla0001DatHash()) { if (manager.IsVanilla0001DatHash()) { MessageBox.Show("Fresh 00.dat/01.dat detected. The setup wizard will now run.", "Game data hash mismatch", MessageBoxButtons.OK, MessageBoxIcon.Information); } else { MessageBox.Show("Game archive has been modified. The setup wizard will now run.", "Game data hash mismatch", MessageBoxButtons.OK, MessageBoxIcon.Information); } SetupWizard.SetupWizard setupWizard = new SetupWizard.SetupWizard(); setupWizard.ShowDialog(); } else if (!BackupManager.c7t7Exist()) // chunk7 and/or texture7 are missing, despite the dathash validating. { MessageBox.Show("To continue, SnakeBite must build a_chunk7.dat and a_texture7.dat from your current archives. The setup wizard will now run.", "Setup required", MessageBoxButtons.OK, MessageBoxIcon.Information); SetupWizard.SetupWizard setupWizard = new SetupWizard.SetupWizard(); setupWizard.ShowDialog(); } if (doCmdLine) { Debug.LogLine("Doing cmd line args"); formMods ModForm = new formMods(); ModForm.Show(); ModForm.Hide(); if (install) { // install ModForm.ProcessInstallMod(installFile, skipCleanup); // install mod } else { // uninstall var mods = manager.GetInstalledMods(); ModEntry mod = mods.FirstOrDefault(entry => entry.Name == installFile); // select mod if (mod != null) { ModForm.ProcessUninstallMod(mod); // uninstall mod } } ModForm.Dispose(); if (closeApp) { return; } } //Application.Run(new formMain()); Application.Run(new formLauncher()); }
private static HashSet <string> MergePacks(ModEntry extractedModEntry, List <string> pullFromVanillas, List <string> pullFromMods) { HashSet <string> modQarZeroPaths = new HashSet <string>(); foreach (ModQarEntry modQar in extractedModEntry.ModQarEntries) { string workingDestination = Path.Combine("_working0", Tools.ToWinPath(modQar.FilePath)); if (!Directory.Exists(Path.GetDirectoryName(workingDestination))) { Directory.CreateDirectory(Path.GetDirectoryName(workingDestination)); } string modQarSource = Path.Combine("_extr", Tools.ToWinPath(modQar.FilePath)); string existingQarSource; if (pullFromMods.FirstOrDefault(e => e == modQar.FilePath) != null) { //Debug.LogLine(string.Format("{0}'s Qar file '{1}' will pull from _working0 (modded)", extractedModEntry.Name, modQar.FilePath)); existingQarSource = workingDestination; } else { int indexToRemove = pullFromVanillas.FindIndex(m => m == modQar.FilePath); // remove from retrievalfilepaths and add to editlist if (indexToRemove >= 0) { //Debug.LogLine(string.Format("{0}'s Qar file '{1}' will pull from _gameFpk (fresh game file)", extractedModEntry.Name, modQar.FilePath)); existingQarSource = Path.Combine("_gameFpk", Tools.ToWinPath(modQar.FilePath)); pullFromVanillas.RemoveAt(indexToRemove); pullFromMods.Add(modQar.FilePath); } else { //Debug.LogLine(string.Format("{0}'s Qar file '{1}' is non-native or not mergeable", extractedModEntry.Name, modQar.FilePath)); existingQarSource = null; if (modQar.FilePath.EndsWith(".fpk") || modQar.FilePath.EndsWith(".fpkd")) { pullFromMods.Add(modQar.FilePath); // for merging non-native fpk files consecutively } } } if (existingQarSource != null) { var pulledPack = GzsLib.ExtractArchive <FpkFile>(existingQarSource, "_build"); var extrPack = GzsLib.ExtractArchive <FpkFile>(modQarSource, "_build"); pulledPack = pulledPack.Union(extrPack).ToList(); //foreach(string file in extrPack) Debug.LogLine(string.Format("{0} is listed in the archive extr", file)); GzsLib.WriteFpkArchive(workingDestination, "_build", pulledPack); } else { File.Copy(modQarSource, workingDestination, true); } if (!modQar.FilePath.Contains(".ftex")) { //Debug.LogLine(string.Format("Adding {0}'s Qar file '{1}' to 00.dat", extractedModEntry.Name, modQar.FilePath)); modQarZeroPaths.Add(Tools.ToWinPath(modQar.FilePath)); } } return(modQarZeroPaths); }
public static bool CheckConflicts(string ModFile) { ModEntry metaData = Tools.ReadMetaData(ModFile); if (metaData == null) { return(false); } // check version conflicts var SBVersion = ModManager.GetSBVersion(); var MGSVersion = ModManager.GetMGSVersion(); SettingsManager manager = new SettingsManager(GamePaths.SnakeBiteSettings); Version modSBVersion = new Version(); Version modMGSVersion = new Version(); try { modSBVersion = metaData.SBVersion.AsVersion(); modMGSVersion = metaData.MGSVersion.AsVersion(); } catch { MessageBox.Show(String.Format("The selected version of {0} was created with an older version of SnakeBite and is no longer compatible, please download the latest version and try again.", metaData.Name), "Mod update required", MessageBoxButtons.OK, MessageBoxIcon.Error); return(false); } // Check if mod requires SB update if (modSBVersion > SBVersion) { MessageBox.Show(String.Format("{0} requires SnakeBite version {1} or newer. Please follow the link on the Settings page to get the latest version.", metaData.Name, metaData.SBVersion), "Update required", MessageBoxButtons.OK, MessageBoxIcon.Error); return(false); } if (modSBVersion < new Version(0, 8, 0, 0)) // 0.8.0.0 { MessageBox.Show(String.Format("The selected version of {0} was created with an older version of SnakeBite and is no longer compatible, please download the latest version and try again.", metaData.Name), "Mod update required", MessageBoxButtons.OK, MessageBoxIcon.Error); return(false); } // Check MGS version compatibility if (!manager.IsUpToDate(modMGSVersion)) { if (MGSVersion > modMGSVersion) { var contInstall = MessageBox.Show(String.Format("{0} appears to be for an older version of MGSV. It is recommended that you check for an updated version before installing.\n\nContinue installation?", metaData.Name), "Game version mismatch", MessageBoxButtons.YesNo, MessageBoxIcon.Warning); if (contInstall == DialogResult.No) { return(false); } } if (MGSVersion < modMGSVersion) { MessageBox.Show(String.Format("{0} requires MGSV version {1}, but your installation is version {2}. Please update MGSV and try again.", metaData.Name, modMGSVersion, MGSVersion), "Update required", MessageBoxButtons.OK, MessageBoxIcon.Error); return(false); } } //end of validity checks Debug.LogLine(String.Format("[Mod] Checking conflicts for {0}", metaData.Name), Debug.LogLevel.Basic); int confCounter = 0; // search installed mods for conflicts var mods = manager.GetInstalledMods(); List <string> conflictingMods = new List <string>(); int confIndex = -1; foreach (ModEntry mod in mods) // iterate through installed mods { foreach (ModFileEntry fileEntry in metaData.ModFileEntries) // iterate external files from new mod { ModFileEntry conflicts = mod.ModFileEntries.FirstOrDefault(entry => Tools.CompareHashes(entry.FilePath, fileEntry.FilePath)); if (conflicts != null) { if (confIndex == -1) { confIndex = mods.IndexOf(mod); } if (!conflictingMods.Contains(mod.Name)) { conflictingMods.Add(mod.Name); } Debug.LogLine(String.Format("[{0}] Conflict in 00.dat: {1}", mod.Name, conflicts.FilePath), Debug.LogLevel.Basic); confCounter++; } } foreach (ModQarEntry qarEntry in metaData.ModQarEntries) // iterate qar files from new mod { if (qarEntry.FilePath.EndsWith(".fpk") || qarEntry.FilePath.EndsWith(".fpkd")) { continue; } ModQarEntry conflicts = mod.ModQarEntries.FirstOrDefault(entry => Tools.CompareHashes(entry.FilePath, qarEntry.FilePath)); if (conflicts != null) { if (confIndex == -1) { confIndex = mods.IndexOf(mod); } if (!conflictingMods.Contains(mod.Name)) { conflictingMods.Add(mod.Name); } Debug.LogLine(String.Format("[{0}] Conflict in 00.dat: {1}", mod.Name, conflicts.FilePath), Debug.LogLevel.Basic); confCounter++; } } foreach (ModFpkEntry fpkEntry in metaData.ModFpkEntries) // iterate fpk files from new mod { ModFpkEntry conflicts = mod.ModFpkEntries.FirstOrDefault(entry => Tools.CompareHashes(entry.FpkFile, fpkEntry.FpkFile) && Tools.CompareHashes(entry.FilePath, fpkEntry.FilePath)); if (conflicts != null) { if (confIndex == -1) { confIndex = mods.IndexOf(mod); } if (!conflictingMods.Contains(mod.Name)) { conflictingMods.Add(mod.Name); } Debug.LogLine(String.Format("[{0}] Conflict in {2}: {1}", mod.Name, conflicts.FilePath, Path.GetFileName(conflicts.FpkFile)), Debug.LogLevel.Basic); confCounter++; } } } // if the mod conflicts, display message if (conflictingMods.Count > 0) { Debug.LogLine(String.Format("[Mod] Found {0} conflicts", confCounter), Debug.LogLevel.Basic); string msgboxtext = "The selected mod conflicts with these mods:\n"; foreach (string Conflict in conflictingMods) { msgboxtext += Conflict + "\n"; } msgboxtext += "\nMore information regarding the conflicts has been output to the logfile."; MessageBox.Show(msgboxtext, "Installation Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return(false); } Debug.LogLine("[Mod] No conflicts found", Debug.LogLevel.Basic); bool sysConflict = false; // check for system file conflicts var gameData = manager.GetGameData(); foreach (ModQarEntry gameQarFile in gameData.GameQarEntries.FindAll(entry => entry.SourceType == FileSource.System)) { if (metaData.ModQarEntries.Count(entry => Tools.ToQarPath(entry.FilePath) == Tools.ToQarPath(gameQarFile.FilePath)) > 0) { sysConflict = true; } } foreach (ModFpkEntry gameFpkFile in gameData.GameFpkEntries.FindAll(entry => entry.SourceType == FileSource.System)) { if (metaData.ModFpkEntries.Count(entry => entry.FilePath == gameFpkFile.FilePath && entry.FpkFile == gameFpkFile.FpkFile) > 0) { sysConflict = true; } } if (sysConflict) { //tex TODO: figure out what it's actually checking and how this can be corrupted string msgboxtext = "The selected mod conflicts with existing MGSV system files,\n"; msgboxtext += "or the snakebite.xml base entries has become corrupt.\n"; msgboxtext += "Please use the 'Restore Backup Game Files' option in Snakebite settings and re-run snakebite\n"; MessageBox.Show(msgboxtext, "SnakeBite", MessageBoxButtons.OK, MessageBoxIcon.Error); return(false); } return(true); }
public static bool InstallMod(string ModFile) { if (!ModManager.ValidInstallPath) return false; // no valid install specified if (!File.Exists(GameArchivePath)) return false; // extract existing DAT file ExtractGameArchive(); // import existing DAT xml QarFile qarXml = new QarFile(); qarXml.LoadFromFile(GameArchiveXmlPath); // extract mod files to temp folder if (Directory.Exists("_temp")) Directory.Delete("_temp", true); FastZip unzipper = new FastZip(); unzipper.ExtractZip(ModFile, "_temp", "(.*?)"); // load mod metadata ModEntry modMetadata = new ModEntry(); modMetadata.ReadFromFile("_temp\\metadata.xml"); File.Delete("_temp\\metadata.xml"); // check for fpk merges List<ModFpkEntry> installedFpkFiles = new List<ModFpkEntry>(); foreach (QarEntry gzsQar in qarXml.QarEntries) { string qarExt = gzsQar.FilePath.Substring(gzsQar.FilePath.LastIndexOf(".") + 1).ToLower(); if (qarExt == "fpk" || qarExt == "fpkd") { // extract FPK and add files to list string fpkFile = GameArchiveDir + "\\" + gzsQar.FilePath; string fpkDir = fpkFile.Replace(".", "_"); GzsTool.GzsTool.Run(fpkFile); List<string> fpkFiles = Directory.GetFiles(fpkDir, "*.*", SearchOption.AllDirectories).ToList(); foreach (string file in fpkFiles) { string fpkFilePath = fpkFile.Substring(GameArchiveDir.Length); fpkFilePath = fpkFilePath.Replace("\\", "/"); string fpkPath = file.Substring(file.LastIndexOf("Assets\\")); fpkPath = "/" + fpkPath.Replace("\\", "/"); installedFpkFiles.Add(new ModFpkEntry() { FilePath = fpkFilePath, FpkFile = fpkPath }); } } } // compare lists and build merge fpk list List<string> mergeFpks = new List<string>(); foreach (ModFpkEntry installedFpk in installedFpkFiles) { foreach (ModEntry mod in GetInstalledMods()) { if (mod.ModFpkEntries.Find(entry => entry.FpkFile == installedFpk.FpkFile) != null) // if the mod has an fpk that should be merged with an installed fpk { if (!mergeFpks.Contains(installedFpk.FpkFile)) { mergeFpks.Add(installedFpk.FpkFile); } } } } if (mergeFpks.Count > 0) { // merge fpks foreach (string fpkFile in mergeFpks) { string fpkPath = Tools.ToQarPath(fpkFile); string gameFpkPath = GameArchiveDir + fpkPath; string gameFpkDir = GameArchiveDir + "\\master\\0\\01\\" + fpkPath.Replace(".", "_"); string modFpkPath = "_temp\\" + fpkPath; string modFpkDir = "_temp\\" + fpkPath.Replace(".", "_"); GzsTool.GzsTool.Run(gameFpkPath); GzsTool.GzsTool.Run(modFpkPath); // load existing xml data FpkFile fpkXml = new FpkFile(); fpkXml.LoadFromFile(gameFpkPath + ".xml"); // generate list of files to move and add to xml List<string> filesToMove = new List<string>(); foreach (ModFpkEntry file in modMetadata.ModFpkEntries.FindAll(entry => entry.FpkFile == fpkFile)) { filesToMove.Add(file.FilePath.Replace("/", "\\")); if (fpkXml.FpkEntries.Count(entry => entry.FilePath == file.FilePath) == 0) { // insert new fpk entries as required fpkXml.FpkEntries.Add(new FpkEntry() { FilePath = fpkFile }); } } // create directories and move files foreach (string file in filesToMove) { string fileDir = (gameFpkDir + file).Substring(0, (gameFpkDir + file).LastIndexOf("\\")); if (!Directory.Exists(fileDir)) { Directory.CreateDirectory(fileDir); } File.Copy(modFpkDir + file, gameFpkDir + file, true); } fpkXml.WriteToFile(gameFpkPath + ".xml"); GzsTool.GzsTool.Run(gameFpkPath + ".xml"); } } // copy files for new DAT foreach (ModQarEntry modQarFile in modMetadata.ModQarEntries) { string fileName = "/" + modQarFile.FilePath.Replace("\\", "/"); string fileDir = (GameArchiveDir + modQarFile.FilePath.Replace("/", "\\")).Substring(0, (GameArchiveDir + modQarFile.FilePath).LastIndexOf("/")); // if file is not already in QAR, add it if (qarXml.QarEntries.Count(entry => entry.FilePath == modQarFile.FilePath) == 0) { qarXml.QarEntries.Add(new QarEntry() { FilePath = modQarFile.FilePath, Compressed = modQarFile.Compressed, Hash = modQarFile.Hash }); } // copy all files that weren't merged FPKS if (!mergeFpks.Contains(fileName)) { if (!Directory.Exists(fileDir)) { Directory.CreateDirectory(fileDir); } File.Copy("_temp\\" + modQarFile.FilePath.Replace("/", "\\"), ModManager.GameArchiveDir + modQarFile.FilePath.Replace("/", "\\"), true); } } // build XML for new DAT qarXml.WriteToFile(GameArchiveXmlPath); // build new DAT GzsTool.GzsTool.Run(GameArchiveXmlPath); // remove temp files Directory.Delete("_temp", true); Directory.Delete(GameArchiveDir, true); File.Delete(GameArchiveXmlPath); UpdateDatHash(); return true; }
public static bool InstallMod(string ModFile) { CleanupFolders(); Debug.LogLine(String.Format("[Mod] Installation started: {0}", ModFile), Debug.LogLevel.Basic); // Extract game archive var zeroFiles = GzsLib.ExtractArchive<QarFile>(ZeroPath, "_working"); // Extract mod data FastZip unzipper = new FastZip(); unzipper.ExtractZip(ModFile, "_extr", "(.*?)"); // Load mod metadata ModEntry metaData = new ModEntry("_extr\\metadata.xml"); // Build a list of FPKs contained in mod List<string> modFpks = new List<string>(); foreach (ModFpkEntry fpkEntry in metaData.ModFpkEntries) { if (!modFpks.Contains(fpkEntry.FpkFile)) modFpks.Add(fpkEntry.FpkFile); } List<string> mergeFpks = new List<string>(); List<ModQarEntry> MergeFiles = new List<ModQarEntry>(); Debug.LogLine("[Mod] Checking existing game data", Debug.LogLevel.Basic); // Check for FPKs in 00.dat foreach (string fpk in modFpks) { string datFile = zeroFiles.FirstOrDefault(file => Tools.CompareHashes(file, fpk)); if (datFile != null) { if (mergeFpks.Contains(Tools.ToQarPath(datFile))) continue; mergeFpks.Add(fpk); MergeFiles.Add(new ModQarEntry() { FilePath = fpk, SourceType = FileSource.Merged, SourceName = "00.dat" }); } } var gameData = GzsLib.ReadBaseData(); var oneFiles = gameData.FileList.FindAll(entry => entry.QarFile == "01.dat"); var baseFiles = gameData.FileList.FindAll(entry => entry.QarFile != "01.dat"); // Check for FPKs in 01.dat foreach (string fpk in modFpks) { GameFile file = oneFiles.FirstOrDefault(entry => entry.FileHash == Tools.NameToHash(fpk)); if (file != null) { if (mergeFpks.Contains(Tools.ToQarPath(file.FilePath))) continue; // Create destination directory string destDirectory = Path.Combine("_working", Path.GetDirectoryName(Tools.ToWinPath(file.FilePath))); if (!Directory.Exists(destDirectory)) Directory.CreateDirectory(destDirectory); // Extract file into dat directory var ex = GzsLib.ExtractFileByHash<QarFile>(Path.Combine(GameDir, "master\\0\\01.dat"), file.FileHash, Path.Combine("_working", Tools.ToWinPath(file.FilePath))); mergeFpks.Add(Tools.ToQarPath(file.FilePath)); MergeFiles.Add(new ModQarEntry() { FilePath = file.FilePath, SourceType = FileSource.Merged, SourceName = "01.dat" }); if (zeroFiles.FirstOrDefault(datFile => Tools.CompareHashes(datFile, file.FilePath)) == null) { zeroFiles.Add(Tools.ToWinPath(file.FilePath)); } } } // Check for FPKs in base data foreach (string fpk in modFpks) { GameFile file = baseFiles.FirstOrDefault(entry => entry.FileHash == Tools.NameToHash(fpk)); if (file != null) { if (mergeFpks.Contains(Tools.ToQarPath(file.FilePath))) continue; // Create destination directory string destDirectory = Path.Combine("_working", Path.GetDirectoryName(Tools.ToWinPath(file.FilePath))); if (!Directory.Exists(destDirectory)) Directory.CreateDirectory(destDirectory); // Extract file into dat directory var ex = GzsLib.ExtractFileByHash<QarFile>(Path.Combine(GameDir, "master\\" + file.QarFile), file.FileHash, Path.Combine("_working", Tools.ToWinPath(file.FilePath))); mergeFpks.Add(Tools.ToQarPath(file.FilePath)); MergeFiles.Add(new ModQarEntry() { FilePath = file.FilePath, SourceType = FileSource.Merged, SourceName = file.QarFile }); if (zeroFiles.FirstOrDefault(datFile => Tools.CompareHashes(datFile, file.FilePath)) == null) { zeroFiles.Add(Tools.ToWinPath(file.FilePath)); } } } Debug.LogLine(String.Format("[Mod] Merging {0} FPK files", MergeFiles.Count), Debug.LogLevel.Basic); var g = SettingsManager.GetGameData(); // Merge FPK files foreach (ModQarEntry gf in MergeFiles) { Debug.LogLine(String.Format("[Mod] Starting merge: {0} ({1})", gf.FilePath, gf.SourceName), Debug.LogLevel.Debug); // Extract game FPK string fpkDatPath = zeroFiles.FirstOrDefault(file => Tools.CompareHashes(file, gf.FilePath)); string fpkPath = Path.Combine("_working", Tools.ToWinPath(fpkDatPath)); var gameFpk = GzsLib.ExtractArchive<FpkFile>(fpkPath, "_gamefpk"); // Extract mod FPK var exFpk = GzsLib.ExtractArchive<FpkFile>(Path.Combine("_extr", Tools.ToWinPath(gf.FilePath)), "_modfpk"); // Add file to gamedata info var q = g.GameQarEntries.FirstOrDefault(entry => entry.FilePath == gf.FilePath); if (q == null) g.GameQarEntries.Add(new ModQarEntry() { FilePath = Tools.ToQarPath(gf.FilePath), SourceType = gf.SourceType, SourceName = gf.SourceName, Hash = Tools.NameToHash(gf.FilePath) }); foreach (string f in gameFpk) { var c = exFpk.FirstOrDefault(entry => Tools.CompareHashes(entry, f)); if (c == null) { if (g.GameFpkEntries.FirstOrDefault(entry => Tools.CompareHashes(entry.FpkFile, gf.FilePath) && Tools.CompareNames(entry.FilePath, f)) == null) { g.GameFpkEntries.Add(new ModFpkEntry() { FpkFile = Tools.ToQarPath(gf.FilePath), FilePath = f, SourceType = gf.SourceType, SourceName = gf.SourceName }); } } } // Merge contents foreach (string fileName in exFpk) { string fileDir = (Path.Combine("_gamefpk", Path.GetDirectoryName(fileName))); string sourceFile = Path.Combine("_modfpk", fileName); string destFile = Path.Combine("_gamefpk", fileName); Debug.LogLine(String.Format("[Mod] Copying file: {0}", fileName), Debug.LogLevel.All); if (!Directory.Exists(fileDir)) Directory.CreateDirectory(fileDir); File.Copy(sourceFile, destFile, true); if (!gameFpk.Contains(fileName)) gameFpk.Add(Tools.ToQarPath(fileName)); } // Rebuild game FPK GzsLib.WriteFpkArchive(fpkPath, "_gamefpk", gameFpk); if (!zeroFiles.Contains(Tools.ToWinPath(gf.FilePath))) zeroFiles.Add(Tools.ToWinPath(gf.FilePath)); Directory.Delete("_modfpk", true); Directory.Delete("_gamefpk", true); Debug.LogLine(String.Format("[Mod] Merge complete"), Debug.LogLevel.Debug); } SettingsManager.SetGameData(g); Debug.LogLine("[Mod] Copying remaining mod files", Debug.LogLevel.Basic); // Copy files for 01.dat, ignoring merged FPKs foreach (ModQarEntry modEntry in metaData.ModQarEntries) { if (!zeroFiles.Contains(Tools.ToWinPath(modEntry.FilePath))) zeroFiles.Add(Tools.ToWinPath(modEntry.FilePath)); if (modEntry.FilePath.Contains(".fpk")) if (mergeFpks.Count(fpk => Tools.CompareHashes(fpk, modEntry.FilePath)) > 0) continue; string sourceFile = Path.Combine("_extr", Tools.ToWinPath(modEntry.FilePath)); string destFile = Path.Combine("_working", Tools.ToWinPath(modEntry.FilePath)); string destDir = Path.GetDirectoryName(destFile); Debug.LogLine(String.Format("[Mod] Copying file: {0}", modEntry.FilePath), Debug.LogLevel.All); if (!Directory.Exists(destDir)) Directory.CreateDirectory(destDir); File.Copy(sourceFile, destFile, true); } // Rebuild 01.dat Debug.LogLine("[Mod] Rebuilding game archive", Debug.LogLevel.Basic); GzsLib.WriteQarArchive(ZeroPath, "_working", zeroFiles, 3150048); SettingsManager.UpdateDatHash(); SettingsManager.AddMod(metaData); Debug.LogLine("[Mod] Running database cleanup", Debug.LogLevel.Debug); CleanupDatabase(); CleanupFolders(); Debug.LogLine("[Mod] Installation finished", Debug.LogLevel.Basic); return true; }