private static void UnmergePackFiles(List <ModQarEntry> partialEditQarEntries, List <ModFpkEntry> partialRemoveFpkEntries) { GameData gameData = SBBuildManager.GetGameData(); List <ModFpkEntry> addedRepairFpkEntries = new List <ModFpkEntry>(); foreach (ModQarEntry partialEditQarEntry in partialEditQarEntries) { // create a list of fpk filepaths that need to be modified for the specific qar file (either restored to vanilla or removed from the pack) List <string> fpkPathsForThisQar = partialRemoveFpkEntries.Where(entry => entry.FpkFile == partialEditQarEntry.FilePath).Select(fpkEntry => Tools.ToWinPath(fpkEntry.FilePath)).ToList(); var fpkReferences = new List <string>();//tex references in fpk that need to be preserved/transfered to the rebuilt fpk // pull the vanilla qar file from the game archive, send to _gameFpk folder string winQarEntryPath = Tools.ToWinPath(partialEditQarEntry.FilePath); string gameQarPath = Path.Combine("_gameFpk", winQarEntryPath); if (partialEditQarEntry.SourceName != null) { string vanillaArchivePath = Path.Combine(GameDir, "master\\" + partialEditQarEntry.SourceName); //Debug.LogLine(string.Format("Pulling {0} from {1}", partialRemoveQarEntry.FilePath, partialRemoveQarEntry.SourceName)); GzsLib.ExtractFileByHash <QarFile>(vanillaArchivePath, partialEditQarEntry.Hash, gameQarPath); fpkReferences = GzsLib.GetFpkReferences(gameQarPath); } // pull the modded qar file from _working0 (assumed to already exist when the uninstall process reads 00.dat), send to _build folder string workingZeroQarPath = Path.Combine("_working0", winQarEntryPath); List <string> moddedFpkFiles = GzsLib.ExtractArchive <FpkFile>(workingZeroQarPath, "_build"); // split the fpk paths for this Qar into two categories: List <string> repairFilePathList = new List <string>(); // files that need to be repaired (aka overwritten by a vanilla file) if (partialEditQarEntry.SourceName != null) { repairFilePathList = GzsLib.ListArchiveContents <FpkFile>(gameQarPath).Intersect(fpkPathsForThisQar).ToList(); } List <string> removeFilePathList = fpkPathsForThisQar.Except(repairFilePathList).ToList(); // files that need to be removed (i.e. files that were non-native to the vanilla Qar) foreach (string repairFilePath in repairFilePathList) { string fpkBuildPath = Path.Combine("_build", repairFilePath); Debug.LogLine(string.Format("[Unmerge Fpk] Extracting repair file: {0}", repairFilePath), Debug.LogLevel.Basic); GzsLib.ExtractFile <FpkFile>(gameQarPath, repairFilePath, fpkBuildPath); // overwrites modded fpk files ModFpkEntry repairEntry = new ModFpkEntry { FpkFile = partialEditQarEntry.FilePath, FilePath = repairFilePath, // this will be a window path SourceType = FileSource.Merged, SourceName = partialEditQarEntry.SourceName }; gameData.GameFpkEntries.Add(repairEntry); addedRepairFpkEntries.Add(repairEntry); } var buildFiles = moddedFpkFiles.Except(removeFilePathList).ToList(); //tex refs werent grabbed from vanilla (or there weren't any in there in that case we're probably doubling the work lol) if (fpkReferences.Count == 0) { fpkReferences = GzsLib.GetFpkReferences(workingZeroQarPath); } GzsLib.WriteFpkArchive(workingZeroQarPath, "_build", buildFiles, fpkReferences); // writes the pack back to _working folder (leaving out the non-native fpk files) foreach (string removeFilePath in removeFilePathList) { int indexToRemove = gameData.GameFpkEntries.FindIndex(entry => entry.FilePath == removeFilePath); if (indexToRemove >= 0) { gameData.GameFpkEntries.RemoveAt(indexToRemove); } } } List <ModEntry> installedMods = SBBuildManager.GetInstalledMods(); foreach (ModEntry installedMod in installedMods) { List <string> qarPathsFound = new List <string>(); foreach (ModFpkEntry addedRepairEntry in addedRepairFpkEntries) { if (installedMod.ModQarEntries.FirstOrDefault(entry => entry.FilePath == addedRepairEntry.FpkFile) == null) { continue; } //Debug.LogLine(string.Format("checking {0} for {1} of {2}", installedMod.Name, addedRepairEntry.FilePath, addedRepairEntry.FpkFile)); if (installedMod.ModFpkEntries.RemoveAll(entry => entry.FilePath == Tools.ToQarPath(addedRepairEntry.FilePath) && entry.FpkFile == addedRepairEntry.FpkFile) > 0) { //Debug.LogLine(string.Format("found {0} of {1} in {2}", addedRepairEntry.FilePath, addedRepairEntry.FpkFile, installedMod.Name)); if (!qarPathsFound.Contains(addedRepairEntry.FpkFile)) { qarPathsFound.Add(addedRepairEntry.FpkFile); } } } foreach (string qarPathFound in qarPathsFound) { if (installedMod.ModFpkEntries.FirstOrDefault(entry => entry.FpkFile == qarPathFound) == null) //when the duplicate fpk file(s) were removed, there was nothing left in the modded qar. { //Debug.LogLine(string.Format("Removing {0} from {1}", qarPathFound, installedMod.Name)); installedMod.ModQarEntries.RemoveAll(entry => entry.FilePath == qarPathFound); // filters the qar file out of the list } } } SBBuildManager.SetInstalledMods(installedMods); SBBuildManager.SetGameData(gameData); }
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)); //TODO: merge referenced from mod archive to (but then that would probably be tricky keeping track of for Unmerge) //I think only fpks have references (not fpkd), but whatev. var fpkReferences = GzsLib.GetFpkReferences(existingQarSource); GzsLib.WriteFpkArchive(workingDestination, "_build", pulledPack, fpkReferences); } 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); }