/// <summary> /// Merges the new mod files with the existing modded files and vanilla game files. /// The resulting file structure is the new _working0 folder to pack as 00.dat /// </summary> private static void InstallMods(List <string> modFilePaths, SettingsManager manager, List <string> pullFromVanillas, List <string> pullFromMods, ref HashSet <string> zeroFiles, ref List <string> oneFilesList, Dictionary <string, bool> pathUpdatesExist) { //Assumption: modded packs have already been extracted to _working0 directory - qarEntryEditList //Assumption: vanilla packs have already been extracted to _gameFpk directory (during AddToSettings) - fpkEntryRetrievalList //theoretically there should be no qar overlap between the _gamefpk(vanilla) and _working0(modded) files FastZip unzipper = new FastZip(); GameData gameData = manager.GetGameData(); foreach (string modFilePath in modFilePaths) { Debug.LogLine($"[Install] Installation started: {Path.GetFileName(modFilePath)}", Debug.LogLevel.Basic); Debug.LogLine($"[Install] Unzipping mod .mgsv ({Tools.GetFileSizeKB(modFilePath)} KB)", Debug.LogLevel.Basic); unzipper.ExtractZip(modFilePath, "_extr", "(.*?)"); Debug.LogLine("[Install] Load mod metadata", Debug.LogLevel.Basic); ModEntry extractedModEntry = new ModEntry("_extr\\metadata.xml"); if (pathUpdatesExist[extractedModEntry.Name]) { Debug.LogLine(string.Format("[Install] Checking for Qar path updates: {0}", extractedModEntry.Name), Debug.LogLevel.Basic); foreach (ModQarEntry modQar in extractedModEntry.ModQarEntries.Where(entry => !entry.FilePath.StartsWith("/Assets/"))) { string unhashedName = HashingExtended.UpdateName(modQar.FilePath); if (unhashedName != null) { Debug.LogLine(string.Format("[Install] Update successful: {0} -> {1}", modQar.FilePath, unhashedName), Debug.LogLevel.Basic); string workingOldPath = Path.Combine("_extr", Tools.ToWinPath(modQar.FilePath)); string workingNewPath = Path.Combine("_extr", Tools.ToWinPath(unhashedName)); if (!Directory.Exists(Path.GetDirectoryName(workingNewPath))) { Directory.CreateDirectory(Path.GetDirectoryName(workingNewPath)); } if (!File.Exists(workingNewPath)) { File.Move(workingOldPath, workingNewPath); } modQar.FilePath = unhashedName; } } } GzsLib.LoadModDictionary(extractedModEntry); ValidateModEntries(ref extractedModEntry); Debug.LogLine("[Install] Check mod FPKs against game .dat fpks", Debug.LogLevel.Basic); zeroFiles.UnionWith(MergePacks(extractedModEntry, pullFromVanillas, pullFromMods)); //foreach (string zeroFile in zeroFiles) Debug.LogLine(string.Format("Contained in zeroFiles: {0}", zeroFile)); Debug.LogLine("[Install] Copying loose textures to 01.", Debug.LogLevel.Basic); InstallLooseFtexs(extractedModEntry, ref oneFilesList); Debug.LogLine("[Install] Copying game dir files", Debug.LogLevel.Basic); InstallGameDirFiles(extractedModEntry, ref gameData); } manager.SetGameData(gameData); }
/// <summary> /// move vanilla 00 files to 01, moves vanilla 01 textures to texture7, cleans snakebite.xml /// as DoWorkEventHandler /// </summary> public static void backgroundWorker_MergeAndCleanup(object sender, DoWorkEventArgs e) { BackgroundWorker mergeProcessor = (BackgroundWorker)sender; try { GzsLib.LoadDictionaries(); ClearBuildFiles(c7Path, t7Path, ZeroPath, OnePath, SnakeBiteSettings, SavePresetPath); ClearSBGameDir(); CleanupFolders(); mergeProcessor.ReportProgress(0, $"Migrating files to new archives ({Tools.GetFileSizeKB(ZeroPath, OnePath)} KB)"); if (!MoveDatFiles()) //moves vanilla 00 files into 01, excluding foxpatch. { Debug.LogLine("[DatMerge] Failed to complete archive migration. Cancelling..."); e.Cancel = true; ClearBuildFiles(c7Path, t7Path, ZeroPath, OnePath); return; } mergeProcessor.ReportProgress(0, $"Modfying foxfs in chunk0.dat ({Tools.GetFileSizeKB(chunk0Path)} KB)"); if (!ModifyFoxfs()) // adds lines to foxfs in chunk0. { Debug.LogLine("[ModifyFoxfs] Failed to complete Foxfs modification. Cancelling..."); e.Cancel = true; ClearBuildFiles(c7Path, t7Path, ZeroPath, OnePath, chunk0Path); return; } mergeProcessor.ReportProgress(0, "Promoting new archives"); PromoteBuildFiles(c7Path, t7Path, ZeroPath, OnePath, chunk0Path); // overwrites existing archives with modified archives mergeProcessor.ReportProgress(0, "Cleaning database"); CleanupDatabase(); } catch (Exception f) { MessageBox.Show(string.Format("An error has occurred while attempting to merge or clean up SnakeBite data: {0}", f), "Exception Occurred", MessageBoxButtons.OK, MessageBoxIcon.Error); Debug.LogLine(string.Format("[MergeAndCleanup] Exception Occurred: {0}", f), Debug.LogLevel.Basic); Debug.LogLine("[MergeAndCleanup] SnakeBite has failed to merge and clean up SnakeBite data", Debug.LogLevel.Basic); e.Cancel = true; try { ClearBuildFiles(c7Path, t7Path, ZeroPath, OnePath, chunk0Path); } catch (Exception g) { Debug.LogLine(string.Format("[MergeAndCleanup] Exception Occurred: {0}", g), Debug.LogLevel.Basic); Debug.LogLine("[MergeAndCleanup] SnakeBite has failed to remove the build files.", Debug.LogLevel.Basic); } return; } }
/// <summary> /// Back up dat files /// as DoWorkEventHandler /// </summary> public static void backgroundWorker_CopyBackupFiles(object sender, DoWorkEventArgs e) { BackgroundWorker backupProcessor = (BackgroundWorker)sender; object param = Path.GetFileName(ZeroPath); backupProcessor.ReportProgress(0, string.Format("{0:n0}", $"{param} ({Tools.GetFileSizeKB(ZeroPath)} KB)")); File.Copy(ZeroPath, ZeroPath + original_ext, true); param = Path.GetFileName(OnePath); backupProcessor.ReportProgress(0, string.Format("{0:n0}", $"{param} ({Tools.GetFileSizeKB(OnePath)} KB)")); File.Copy(OnePath, OnePath + original_ext, true); param = Path.GetFileName(chunk0Path); backupProcessor.ReportProgress(0, string.Format("{0:n0}", $"{param} ({Tools.GetFileSizeKB(chunk0Path)} KB)")); File.Copy(chunk0Path, chunk0Path + original_ext, true); }