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); }
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); }
}//InstallGameDirFiles private static void AddToSettingsFpk(List <ModEntry> installEntryList, SettingsManager manager, List <Dictionary <ulong, GameFile> > allQarGameFiles, out List <string> PullFromVanillas, out List <string> pullFromMods, out Dictionary <string, bool> pathUpdatesExist) { GameData gameData = manager.GetGameData(); pathUpdatesExist = new Dictionary <string, bool>(); List <string> newModQarEntries = new List <string>(); List <string> modQarFiles = manager.GetModQarFiles(); pullFromMods = new List <string>(); foreach (ModEntry modToInstall in installEntryList) { Dictionary <string, string> newNameDictionary = new Dictionary <string, string>(); int foundUpdate = 0; foreach (ModQarEntry modQar in modToInstall.ModQarEntries.Where(entry => !entry.FilePath.StartsWith("/Assets/"))) { //Debug.LogLine(string.Format("Attempting to update Qar filename: {0}", modQar.FilePath), Debug.LogLevel.Basic); string unhashedName = HashingExtended.UpdateName(modQar.FilePath); if (unhashedName != null) { //Debug.LogLine(string.Format("Success: {0}", unhashedName), Debug.LogLevel.Basic); newNameDictionary.Add(modQar.FilePath, unhashedName); foundUpdate++; modQar.FilePath = unhashedName; if (!pathUpdatesExist.ContainsKey(modToInstall.Name)) { pathUpdatesExist.Add(modToInstall.Name, true); } else { pathUpdatesExist[modToInstall.Name] = true; } } } if (foundUpdate > 0) { foreach (ModFpkEntry modFpkEntry in modToInstall.ModFpkEntries) { string unHashedName; if (newNameDictionary.TryGetValue(modFpkEntry.FpkFile, out unHashedName)) { modFpkEntry.FpkFile = unHashedName; } } } else if (!pathUpdatesExist.ContainsKey(modToInstall.Name)) { pathUpdatesExist.Add(modToInstall.Name, false); } manager.AddMod(modToInstall); //foreach (ModQarEntry modqar in modToInstall.ModQarEntries) Debug.LogLine("Mod Qar in modToInstall: " + modqar.FilePath); foreach (ModQarEntry modQarEntry in modToInstall.ModQarEntries) // add qar entries (fpk, fpkd) to GameData if they don't already exist { string modQarFilePath = modQarEntry.FilePath; if (!(modQarFilePath.EndsWith(".fpk") || modQarFilePath.EndsWith(".fpkd"))) { continue; // only pull for Qar's with Fpk's } if (modQarFiles.Any(entry => entry == modQarFilePath)) { pullFromMods.Add(modQarFilePath); //Debug.LogLine("Pulling from 00.dat: {0} " + modQarFilePath); } else if (!newModQarEntries.Contains(modQarFilePath)) { newModQarEntries.Add(modQarFilePath); //Debug.LogLine("Pulling from base archives: {0} " + modQarFilePath); } } } //Debug.LogLine(string.Format("Foreach nest 1 complete")); List <ModFpkEntry> newModFpkEntries = new List <ModFpkEntry>(); foreach (ModEntry modToInstall in installEntryList) { foreach (ModFpkEntry modFpkEntry in modToInstall.ModFpkEntries) { //Debug.LogLine(string.Format("Checking out {0} from {1}", modFpkEntry.FilePath, modFpkEntry.FpkFile)); if (newModQarEntries.Contains(modFpkEntry.FpkFile)) // it isn't already part of the snakebite environment { //Debug.LogLine(string.Format("seeking repair files around {0}", modFpkEntry.FilePath)); newModFpkEntries.Add(modFpkEntry); } else { //Debug.LogLine(string.Format("Removing {0} from gameFpkEntries so it will only be listed in the mod's entries", modFpkEntry.FilePath)); int indexToRemove = gameData.GameFpkEntries.FindIndex(m => m.FilePath == Tools.ToWinPath(modFpkEntry.FilePath)); // this will remove the gamedata's listing of the file under fpkentries (repair entries), so the filepath will only be listed in the modentry if (indexToRemove >= 0) { gameData.GameFpkEntries.RemoveAt(indexToRemove); } } } } //Debug.LogLine(string.Format("Foreach nest 2 complete")); HashSet <ulong> mergeFpkHashes = new HashSet <ulong>(); PullFromVanillas = new List <string>(); var repairFpkEntries = new List <ModFpkEntry>(); foreach (ModFpkEntry newFpkEntry in newModFpkEntries) // this will add the fpkentry listings (repair entries) to the settings xml { //Debug.LogLine(string.Format("checking {0} for repairs", newFpkEntry.FilePath)); ulong packHash = Tools.NameToHash(newFpkEntry.FpkFile); if (mergeFpkHashes.Contains(packHash)) { continue; // the process has already plucked this particular qar file } foreach (var archiveQarGameFiles in allQarGameFiles) // check every archive (except 00) to see if the particular qar file already exists { //Debug.LogLine(string.Format("checking archive for an existing qar file")); if (archiveQarGameFiles.Count > 0) { GameFile existingPack = null; archiveQarGameFiles.TryGetValue(packHash, out existingPack); if (existingPack != null) // the qar file is found { //Debug.LogLine(string.Format("Qar file {0} found in {1}. adding to gameqarentries", newFpkEntry.FpkFile, existingPack.QarFile)); mergeFpkHashes.Add(packHash); gameData.GameQarEntries.Add(new ModQarEntry { FilePath = newFpkEntry.FpkFile, SourceType = FileSource.Merged, SourceName = existingPack.QarFile, Hash = existingPack.FileHash }); PullFromVanillas.Add(newFpkEntry.FpkFile); string windowsFilePath = Tools.ToWinPath(newFpkEntry.FpkFile); // Extract the pack file from the vanilla game files, place into _gamefpk for future use string sourceArchive = Path.Combine(GameDir, "master\\" + existingPack.QarFile); string workingPath = Path.Combine("_gameFpk", windowsFilePath); if (!Directory.Exists(Path.GetDirectoryName(workingPath))) { Directory.CreateDirectory(Path.GetDirectoryName(workingPath)); } GzsLib.ExtractFileByHash <QarFile>(sourceArchive, existingPack.FileHash, workingPath); // extracts the specific .fpk from the game data foreach (string listedFile in GzsLib.ListArchiveContents <FpkFile>(workingPath)) { repairFpkEntries.Add(new ModFpkEntry { FpkFile = newFpkEntry.FpkFile, FilePath = listedFile, SourceType = FileSource.Merged, SourceName = existingPack.QarFile }); //Debug.LogLine(string.Format("File Listed: {0} in {1}", extractedFile, newFpkEntry.FpkFile)); } break; } } } } //Debug.LogLine(string.Format("Foreach nest 3 complete")); foreach (ModFpkEntry newFpkEntry in newModFpkEntries) // finally, strip away the modded entries from the repair entries { //Debug.LogLine(string.Format("checking to remove {0} from gamefpkentries", Tools.ToWinPath(newFpkEntry.FilePath))); int indexToRemove = repairFpkEntries.FindIndex(m => m.FilePath == Tools.ToWinPath(newFpkEntry.FilePath)); if (indexToRemove >= 0) { repairFpkEntries.RemoveAt(indexToRemove); } } gameData.GameFpkEntries = gameData.GameFpkEntries.Union(repairFpkEntries).ToList(); manager.SetGameData(gameData); }
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); }