private async void Menu_Backup_Click(object sender, RoutedEventArgs e) { var result = FlexibleMessageBox.Show("This will create a backup of the index files TexTools can modify (01, 04, 06)\n\n" + "Do you want to Backup Now?" + "\n\nWarning:\nIn order to create a clean backup, all active modifications will be set to disabled, they will have to be re-enabled manually.", "Backup Index Files", MessageBoxButtons.YesNo, MessageBoxIcon.Information); if (result == System.Windows.Forms.DialogResult.Yes) { var gameDirectory = new DirectoryInfo(Settings.Default.FFXIV_Directory); var backupDirectory = new DirectoryInfo(Properties.Settings.Default.Backup_Directory); var indexFiles = new XivDataFile[] { XivDataFile._04_Chara, XivDataFile._06_Ui, XivDataFile._01_Bgcommon }; var index = new Index(gameDirectory); var modding = new Modding(gameDirectory); if (index.IsIndexLocked(XivDataFile._0A_Exd)) { FlexibleMessageBox.Show("Unable to create backup while game is running.", $"Backup Creation Failed", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } try { // Toggle off all mods modding.ToggleAllMods(false); } catch (Exception ex) { FlexibleMessageBox.Show($"Unable to create backup files.\n\nError Message:\n{ex.Message}", $"Backup Creation Failed", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } foreach (var xivDataFile in indexFiles) { try { File.Copy($"{gameDirectory.FullName}\\{xivDataFile.GetDataFileName()}.win32.index", $"{backupDirectory}\\{xivDataFile.GetDataFileName()}.win32.index", true); File.Copy($"{gameDirectory.FullName}\\{xivDataFile.GetDataFileName()}.win32.index2", $"{backupDirectory}\\{xivDataFile.GetDataFileName()}.win32.index2", true); } catch (Exception ex) { FlexibleMessageBox.Show($"Unable to create backups.\n\nError: {ex.Message}", $"Backup Creation Failed", MessageBoxButtons.OK, MessageBoxIcon.Error); } } await this.ShowMessageAsync("Backup Complete", "The index files have been successfully backed up"); } }
private async void Menu_Backup_Click(object sender, RoutedEventArgs e) { var result = FlexibleMessageBox.Show(UIMessages.CreateBackupsMessage, UIMessages.CreateBackupsTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Information); if (result == System.Windows.Forms.DialogResult.Yes) { var gameDirectory = new DirectoryInfo(Settings.Default.FFXIV_Directory); var backupDirectory = new DirectoryInfo(Properties.Settings.Default.Backup_Directory); var indexFiles = new XivDataFile[] { XivDataFile._04_Chara, XivDataFile._06_Ui, XivDataFile._01_Bgcommon }; var index = new Index(gameDirectory); var modding = new Modding(gameDirectory); if (index.IsIndexLocked(XivDataFile._0A_Exd)) { FlexibleMessageBox.Show(UIMessages.IndexLockedBackupFailedMessage, UIMessages.BackupFailedTitle, MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } try { // Toggle off all mods await modding.ToggleAllMods(false); } catch (Exception ex) { FlexibleMessageBox.Show(string.Format(UIMessages.BackupFailedErrorMessage, ex.Message), UIMessages.BackupFailedTitle, MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } foreach (var xivDataFile in indexFiles) { try { File.Copy($"{gameDirectory.FullName}\\{xivDataFile.GetDataFileName()}.win32.index", $"{backupDirectory}\\{xivDataFile.GetDataFileName()}.win32.index", true); File.Copy($"{gameDirectory.FullName}\\{xivDataFile.GetDataFileName()}.win32.index2", $"{backupDirectory}\\{xivDataFile.GetDataFileName()}.win32.index2", true); } catch (Exception ex) { FlexibleMessageBox.Show(string.Format(UIMessages.BackupFailedErrorMessage, ex.Message), UIMessages.BackupFailedTitle, MessageBoxButtons.OK, MessageBoxIcon.Error); } } await this.ShowMessageAsync(UIMessages.BackupCompleteTitle, UIMessages.BackupCompleteMessage); } }
public Task BackupIndexFiles(DirectoryInfo backupsDirectory) { return(Task.Run(async() => { var indexFiles = new XivDataFile[] { XivDataFile._0A_Exd, XivDataFile._04_Chara, XivDataFile._06_Ui, XivDataFile._01_Bgcommon }; var index = new Index(_gameDirectory); var modding = new Modding(_gameDirectory); if (index.IsIndexLocked(XivDataFile._0A_Exd)) { throw new Exception("Index files are in use by another process."); } try { // Toggle off all mods await modding.ToggleAllMods(false); } catch { throw new Exception("Failed to disable mods.\n\n" + "Please check For problems by selecting Help -> Check For Problems"); } var originalFiles = Directory.GetFiles(_gameDirectory.FullName); foreach (var originalFile in originalFiles) { try { if (originalFile.Contains(".win32.index")) { File.Copy(originalFile, $"{backupsDirectory}/{Path.GetFileName(originalFile)}", true); } } catch (Exception ex) { throw new Exception("Failed to copy index files.\n\n" + ex.Message); } } })); }
private Task CheckGameVersion() { return(Task.Run(async() => { var applicationVersion = FileVersionInfo .GetVersionInfo(System.Reflection.Assembly.GetExecutingAssembly().Location).FileVersion; Version ffxivVersion = null; var needsNewBackup = false; var backupMessage = ""; var modding = new Modding(_gameDirectory); var backupDirectory = new DirectoryInfo(Properties.Settings.Default.Backup_Directory); var versionFile = $"{_gameDirectory.Parent.Parent.FullName}\\ffxivgame.ver"; if (File.Exists(versionFile)) { var versionData = File.ReadAllLines(versionFile); ffxivVersion = new Version(versionData[0].Substring(0, versionData[0].LastIndexOf("."))); } else { FlexibleMessageBox.Show(_win32Window, UIMessages.GameVersionErrorMessage, string.Format(UIMessages.GameVersionErrorTitle, applicationVersion), MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } if (string.IsNullOrEmpty(Properties.Settings.Default.FFXIV_Version)) { Properties.Settings.Default.FFXIV_Version = ffxivVersion.ToString(); Properties.Settings.Default.Save(); needsNewBackup = true; backupMessage = UIMessages.NewInstallDetectedBackupMessage; } else { var versionCheck = new Version(Properties.Settings.Default.FFXIV_Version); if (ffxivVersion > versionCheck) { needsNewBackup = true; backupMessage = UIMessages.NewerVersionDetectedBackupMessage; } } if (!Directory.Exists(backupDirectory.FullName)) { FlexibleMessageBox.Show(_win32Window, UIMessages.BackupsDirectoryErrorMessage, UIMessages.BackupFailedTitle, MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } if (Directory.GetFiles(backupDirectory.FullName).Length == 0) { needsNewBackup = true; backupMessage = UIMessages.NoBackupsFoundMessage; } if (needsNewBackup) { var indexFiles = new XivDataFile[] { XivDataFile._04_Chara, XivDataFile._06_Ui, XivDataFile._01_Bgcommon }; if (FlexibleMessageBox.Show(_win32Window, backupMessage, UIMessages.CreateBackupTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes) { if (_index.IsIndexLocked(XivDataFile._0A_Exd)) { FlexibleMessageBox.Show(_win32Window, UIMessages.IndexLockedBackupFailedMessage, UIMessages.BackupFailedTitle, MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } try { // Toggle off all mods await modding.ToggleAllMods(false); } catch (Exception ex) { FlexibleMessageBox.Show(_win32Window, string.Format(UIMessages.BackupFailedErrorMessage, ex.Message), UIMessages.BackupFailedTitle, MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } foreach (var xivDataFile in indexFiles) { try { File.Copy($"{_gameDirectory.FullName}\\{xivDataFile.GetDataFileName()}.win32.index", $"{backupDirectory}\\{xivDataFile.GetDataFileName()}.win32.index", true); File.Copy($"{_gameDirectory.FullName}\\{xivDataFile.GetDataFileName()}.win32.index2", $"{backupDirectory}\\{xivDataFile.GetDataFileName()}.win32.index2", true); } catch (Exception e) { FlexibleMessageBox.Show(_win32Window, string.Format(UIMessages.BackupFailedErrorMessage, e.Message), UIMessages.BackupFailedTitle, MessageBoxButtons.OK, MessageBoxIcon.Error); } } Properties.Settings.Default.FFXIV_Version = ffxivVersion.ToString(); Properties.Settings.Default.Save(); } } })); }
private void CheckGameVersion() { var applicationVersion = FileVersionInfo.GetVersionInfo(System.Reflection.Assembly.GetExecutingAssembly().Location).FileVersion; Version ffxivVersion = null; var needsNewBackup = false; var backupMessage = ""; var modding = new Modding(_gameDirectory); var backupDirectory = new DirectoryInfo(Properties.Settings.Default.Backup_Directory); var versionFile = $"{_gameDirectory.Parent.Parent.FullName}\\ffxivgame.ver"; if (File.Exists(versionFile)) { var versionData = File.ReadAllLines(versionFile); ffxivVersion = new Version(versionData[0].Substring(0, versionData[0].LastIndexOf("."))); } else { FlexibleMessageBox.Show("TexTools was unable to determine the game version.", $"Version Check Error {applicationVersion}", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } if (string.IsNullOrEmpty(Properties.Settings.Default.FFXIV_Version)) { Properties.Settings.Default.FFXIV_Version = ffxivVersion.ToString(); Properties.Settings.Default.Save(); needsNewBackup = true; backupMessage = "New TexTools Install Detected. \nWould you like to create a new backup of your index files now? (Recommended)"; } else { var versionCheck = new Version(Properties.Settings.Default.FFXIV_Version); if (ffxivVersion > versionCheck) { needsNewBackup = true; backupMessage = "A newer version of FFXIV was detected. \nWould you like to create a new backup of your index files now? (Recommended) \n\nWarning:\nIn order to create a clean backup, all active modifications will be set to disabled, they will have to be re-enabled manually."; } } if (!Directory.Exists(backupDirectory.FullName)) { FlexibleMessageBox.Show("Unable to find backup directory", $"Backup Creation Failed {applicationVersion}", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } if (Directory.GetFiles(backupDirectory.FullName).Length == 0) { needsNewBackup = true; backupMessage = "No Index Backups were found. \nWould you like to create a new backup of your index files now? (Recommended) \n\nWarning:\nIn order to create a clean backup, all active modifications will be set to disabled, they will have to be re-enabled manually."; } if (needsNewBackup) { var indexFiles = new XivDataFile[] { XivDataFile._04_Chara, XivDataFile._06_Ui, XivDataFile._01_Bgcommon }; var index = new Index(_gameDirectory); if (MessageBox.Show(backupMessage, "Create Backup?", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes) { try { // Toggle off all mods modding.ToggleAllMods(false); } catch (Exception ex) { FlexibleMessageBox.Show($"Unable to create backup files.\n\nError Message:\n{ex.Message}", $"Backup Creation Failed {applicationVersion}", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } if (index.IsIndexLocked(XivDataFile._0A_Exd)) { FlexibleMessageBox.Show("Unable to create backup while game is running.", $"Backup Creation Failed {applicationVersion}", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } foreach (var xivDataFile in indexFiles) { try { File.Copy($"{_gameDirectory.FullName}\\{xivDataFile.GetDataFileName()}.win32.index", $"{backupDirectory}\\{xivDataFile.GetDataFileName()}.win32.index", true); File.Copy($"{_gameDirectory.FullName}\\{xivDataFile.GetDataFileName()}.win32.index2", $"{backupDirectory}\\{xivDataFile.GetDataFileName()}.win32.index2", true); } catch (Exception e) { FlexibleMessageBox.Show($"Unable to create backups.\n\nError: {e.Message}", $"Backup Creation Failed {applicationVersion}", MessageBoxButtons.OK, MessageBoxIcon.Error); } } } } }
public Task PerformStartOver(DirectoryInfo backupsDirectory, IProgress <string> progress = null, XivLanguage language = XivLanguage.None) { return(Task.Run(async() => { var modding = new Modding(_gameDirectory); var backupsRestored = false; // Stop the cache worker since we're blowing up the entire index file and db anyways. // The cache rebuild will start it up again after the cache is rebuilt. XivCache.CacheWorkerEnabled = false; try { // Try restoring the indexes FIRST. backupsRestored = await RestoreBackups(backupsDirectory); progress?.Report("Restoring index file backups..."); if (!backupsRestored) { throw new Exception("Start Over Failed: Index backups missing/outdated."); } } catch (Exception ex) { try { // If the index restore failed, try just disabling. await modding.DeleteAllFilesAddedByTexTools(); await modding.ToggleAllMods(false); progress?.Report("Index restore failed, attempting to delete all mods instead..."); } catch { throw new Exception("Start Over Failed: Index Backups Invalid and Unable to Disable all mods."); } } finally { progress?.Report("Deleting modded dat files..."); var dat = new Dat(_gameDirectory); // Delete modded dat files foreach (var xivDataFile in (XivDataFile[])Enum.GetValues(typeof(XivDataFile))) { var datFiles = await dat.GetModdedDatList(xivDataFile); foreach (var datFile in datFiles) { File.Delete(datFile); } if (datFiles.Count > 0) { await RepairIndexDatCounts(xivDataFile); } } progress?.Report("Cleaning up mod list..."); var modListDirectory = new DirectoryInfo(Path.Combine(_gameDirectory.Parent.Parent.FullName, XivStrings.ModlistFilePath)); // Delete mod list File.Delete(modListDirectory.FullName); modding.CreateModlist(); progress?.Report("Rebuilding Cache..."); await Task.Run(async() => { XivCache.RebuildCache(); }); } })); }
public Task PerformStartOver(DirectoryInfo backupsDirectory, IProgress <string> progress = null, XivLanguage language = XivLanguage.None) { return(Task.Run(async() => { progress?.Report("Deleting mods..."); var modding = new Modding(_gameDirectory); var backupsRestored = false; try { // Try to restore the index entries to their original values by deleting any files added by TexTools // and setting mods to disabled await modding.DeleteAllFilesAddedByTexTools(); await modding.ToggleAllMods(false); progress?.Report("Restoring index file backups..."); } catch { // If an exception occurred due to a corrupted modlist which couldn't be deserealized restore the backup index // files by force backupsRestored = await RestoreBackups(backupsDirectory); if (!backupsRestored) { throw new Exception("Start Over Failed: Index backups missing/outdated."); } } finally { // If no exception occured, restore the backups anyway just to be safe but don't throw an exception if it fails // due to outdated or missing backups since setting back the original index values should be enough hopefully if (!backupsRestored) { backupsRestored = await RestoreBackups(backupsDirectory); // If backups were not restored that means they were missing/outdated so try to make new backups now if (!backupsRestored) { try { await BackupIndexFiles(backupsDirectory); } catch (Exception ex) { throw new Exception("Start Over Failed: Failed to update outdated backups.\n\n" + ex.Message); } } } progress?.Report("Deleting modded dat files..."); var dat = new Dat(_gameDirectory); // Delete modded dat files foreach (var xivDataFile in (XivDataFile[])Enum.GetValues(typeof(XivDataFile))) { var datFiles = await dat.GetModdedDatList(xivDataFile); foreach (var datFile in datFiles) { File.Delete(datFile); } if (datFiles.Count > 0) { await RepairIndexDatCounts(xivDataFile); } } progress?.Report("Cleaning up mod list..."); var modListDirectory = new DirectoryInfo(Path.Combine(_gameDirectory.Parent.Parent.FullName, XivStrings.ModlistFilePath)); // Delete mod list File.Delete(modListDirectory.FullName); modding.CreateModlist(); progress?.Report("Rebuilding Cache..."); await Task.Run(async() => { var _cache = new XivCache(_gameDirectory, language); _cache.RebuildCache(); }); } })); }
/// <summary> /// Performs post-patch modlist corrections and validation, prompting user also to generate backups after a successful completion. /// </summary> /// <returns></returns> public async Task DoPostPatchCleanup() { FlexibleMessageBox.Show(_mainWindow.Win32Window, UIMessages.PatchDetectedMessage, "Post Patch Cleanup Starting", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); MainWindow.MakeHighlander(); var resetLumina = false; await _mainWindow.LockUi("Performing Post-Patch Maintenence", "This may take a few minutes if you have many mods installed.", this); var gi = XivCache.GameInfo; if (XivCache.GameInfo.UseLumina) { resetLumina = true; XivCache.SetGameInfo(gi.GameDirectory, gi.GameLanguage, gi.DxMode, false, false, gi.LuminaDirectory, gi.UseLumina); } var workerStatus = XivCache.CacheWorkerEnabled; if (workerStatus) { // Stop the cache worker if it's running. XivCache.CacheWorkerEnabled = false; } try { var modding = new Modding(_gameDirectory); var _index = new Index(_gameDirectory); var _dat = new Dat(_gameDirectory); var validTypes = new List <int>() { 2, 3, 4 }; // We have to do a few things here. // 1. Save a list of what mods were enabled. // 2. Go through and validate everything that says it is enabled actually is enabled, or mark it as disabled and update its original index offset if it is not. // 3. Prompt the user for either a full disable and backup creation, or a restore to normal state (re-enable anything that was enabled before but is not now) var modList = modding.GetModList(); Dictionary <XivDataFile, IndexFile> indexFiles = new Dictionary <XivDataFile, IndexFile>(); // Cache our currently enabled stuff. List <Mod> enabledMods = modList.Mods.Where(x => x.enabled == true).ToList(); var toRemove = new List <Mod>(); foreach (var mod in modList.Mods) { if (!String.IsNullOrEmpty(mod.fullPath)) { var df = IOUtil.GetDataFileFromPath(mod.fullPath); if (!indexFiles.ContainsKey(df)) { indexFiles[df] = await _index.GetIndexFile(df); } var index1Value = indexFiles[df].Get8xDataOffset(mod.fullPath); var index2Value = indexFiles[df].Get8xDataOffsetIndex2(mod.fullPath); var oldOriginalOffset = mod.data.originalOffset; var modOffset = mod.data.modOffset; // In any event where an offset does not match either of our saved offsets, we must assume this is a new // default file offset for post-patch. if (index1Value != oldOriginalOffset && index1Value != modOffset && index1Value != 0) { // Index 1 value is our new base offset. var type = _dat.GetFileType(index1Value, df); // Make sure the file it's trying to point to is actually valid. if (validTypes.Contains(type)) { mod.data.originalOffset = index1Value; mod.enabled = false; } else { // Oh dear. The new index is f****d. Is the old Index Ok? type = _dat.GetFileType(oldOriginalOffset, df); if (validTypes.Contains(type) && oldOriginalOffset != 0) { // Old index is fine, so keep using that. // But mark the index value as invalid, so that we stomp on the index value after this. index1Value = -1; mod.enabled = false; } else { // Okay... Maybe the new Index2 Value? if (index2Value != 0) { type = _dat.GetFileType(index2Value, df); if (validTypes.Contains(type)) { // Set the index 1 value to invalid so that the if later down the chain stomps the index1 value. index1Value = -1; mod.data.originalOffset = index2Value; mod.enabled = false; } else { // We be f****d. throw new Exception("Unable to determine working original offset for file:" + mod.fullPath); } } else { // We be f****d. throw new Exception("Unable to determine working original offset for file:" + mod.fullPath); } } } } else if (index2Value != oldOriginalOffset && index2Value != modOffset && index2Value != 0) { // Our Index 1 was normal, but our Index 2 is changed to an unknown value. // If the index 2 points to a valid file, we must assume that this new file // is our new base data offset. var type = _dat.GetFileType(index2Value, df); if (validTypes.Contains(type) && index2Value != 0) { mod.data.originalOffset = index2Value; mod.enabled = false; } else { // Oh dear. The new index is f****d. Is the old Index Ok? type = _dat.GetFileType(oldOriginalOffset, df); if (validTypes.Contains(type) && oldOriginalOffset != 0) { // Old index is fine, so keep using that, but set the index2 value to invalid to ensure we // stomp on the current broken index value. index2Value = -1; } else { // We be f****d. throw new Exception("Unable to determine working original offset for file:" + mod.fullPath); } } } // Indexes don't match. This can occur if SE adds something to index2 that didn't exist in index2 before. if (index1Value != index2Value && index2Value != 0) { // We should never actually get to this state for file-addition mods. If we do, uh.. I guess correct the indexes and yolo? // ( Only way we get here is if SE added a new file at the same name as a file the user had created via modding, in which case, it's technically no longer a file addition mod ) indexFiles[df].SetDataOffset(mod.fullPath, mod.data.originalOffset); index1Value = mod.data.originalOffset; index2Value = mod.data.originalOffset; mod.enabled = false; } // Set it to the corrected state. if (index1Value == mod.data.modOffset) { mod.enabled = true; } else { mod.enabled = false; } // Perform a basic file type check on our results. var fileType = _dat.GetFileType(mod.data.modOffset, IOUtil.GetDataFileFromPath(mod.fullPath)); var originalFileType = _dat.GetFileType(mod.data.modOffset, IOUtil.GetDataFileFromPath(mod.fullPath)); if (!validTypes.Contains(fileType) || mod.data.modOffset == 0) { // Mod data is busted. Fun. toRemove.Add(mod); } if ((!validTypes.Contains(originalFileType)) || mod.data.originalOffset == 0) { if (mod.IsCustomFile()) { // Okay, in this case this is recoverable as the mod is a custom addition anyways, so we can just delete it. if (!toRemove.Contains(mod)) { toRemove.Add(mod); } } else { // Update ended up with us unable to find a working offset. Double fun. throw new Exception("Unable to determine working offset for file:" + mod.fullPath); } } } // Okay, this mod is now represented in the modlist in it's actual post-patch index state. var datNum = (int)((mod.data.modOffset / 8) & 0x0F) / 2; var dat = XivDataFiles.GetXivDataFile(mod.datFile); var originalDats = await _dat.GetUnmoddedDatList(dat); var datPath = $"{dat.GetDataFileName()}{Dat.DatExtension}{datNum}"; // Test for SE Dat file rollover. if (originalDats.Contains(datPath)) { // Shit. This means that the dat file where this mod lived got eaten by SE. We have to destroy the modlist entry at this point. toRemove.Add(mod); } } // Save any index changes we made. foreach (var dkv in indexFiles) { await _index.SaveIndexFile(dkv.Value); } // The modlist is now saved in its current index-represented post patch state. modding.SaveModList(modList); // We now need to clear out any mods that are irreparably f****d, and clear out all of our // internal data files so we can rebuild them later. var internalFiles = modList.Mods.Where(x => x.IsInternal()); toRemove.AddRange(internalFiles); if (toRemove.Count > 0) { var removedString = ""; // Soft-Disable all metadata mods, since we're going to purge their internal file entries. var metadata = modList.Mods.Where(x => x.fullPath.EndsWith(".meta") || x.fullPath.EndsWith(".rgsp")); foreach (var mod in metadata) { var df = IOUtil.GetDataFileFromPath(mod.fullPath); await modding.ToggleModUnsafe(false, mod, true, false, indexFiles[df], modList); } foreach (var mod in toRemove) { if (mod.data.modOffset == 0 || mod.data.originalOffset == 0) { if (mod.data.originalOffset == 0 && mod.enabled) { // This is awkward. We have a mod whose data got bashed, but has no valid original offset to restore. // So the indexes here are f****d if we do, f****d if we don't. throw new Exception("Patch-Broken file has no valid index to restore. Clean Index Restoration required."); } modList.Mods.Remove(mod); enabledMods.Remove(mod); removedString += mod.fullPath + "\n"; } else { if (mod.enabled) { var df = IOUtil.GetDataFileFromPath(mod.fullPath); await modding.ToggleModUnsafe(false, mod, true, false, indexFiles[df], modList); } modList.Mods.Remove(mod); // Since we're deleting this entry entirely, we can't leave it in the other cached list either to get re-enabled later. enabledMods.Remove(mod); if (!mod.IsInternal()) { removedString += mod.fullPath + "\n"; } } } // Save the index files and modlist again now that we've removed all the invalid entries. foreach (var dkv in indexFiles) { await _index.SaveIndexFile(dkv.Value); } modding.SaveModList(modList); // Show the user a message if we purged any real files. if (toRemove.Any(x => !String.IsNullOrEmpty(x.fullPath) && !x.IsInternal())) { var text = String.Format(UIMessages.PatchDestroyedFiles, removedString); FlexibleMessageBox.Show(_mainWindow.Win32Window, text, "Destroyed Files Notification", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1); } } // Always create clean index backups after this process is completed. _mainWindow.LockProgress.Report("Disabling Mods..."); await modding.ToggleAllMods(false); _mainWindow.LockProgress.Report("Creating Index Backups..."); var pc = new ProblemChecker(_gameDirectory); DirectoryInfo backupDir; try { Directory.CreateDirectory(Settings.Default.Backup_Directory); backupDir = new DirectoryInfo(Settings.Default.Backup_Directory); } catch { throw new Exception("Unable to create index backups.\nThe Index Backup directory is invalid or inaccessible: " + Settings.Default.Backup_Directory); } await pc.BackupIndexFiles(backupDir); // Now restore the modlist enable/disable state back to how the user had it before. _mainWindow.LockProgress.Report("Re-Enabling mods..."); // Re-enable things. await modding.ToggleMods(true, enabledMods.Select(x => x.fullPath)); FlexibleMessageBox.Show(_mainWindow.Win32Window, UIMessages.PostPatchComplete, "Post-Patch Process Complete", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); } catch (Exception Ex) { // Show the user the error, then let them go about their business of fixing things. FlexibleMessageBox.Show(_mainWindow.Win32Window, String.Format(UIMessages.PostPatchError, Ex.Message), "Post-Patch Failure", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); } finally { if (resetLumina) { // Reset lumina mode back to on if we disabled it to perform update checks. XivCache.SetGameInfo(gi.GameDirectory, gi.GameLanguage, gi.DxMode, true, false, gi.LuminaDirectory, true); } XivCache.CacheWorkerEnabled = workerStatus; await _mainWindow.UnlockUi(this); } }
/// <summary> /// Event handler for the start over menu item clicked /// </summary> private async void Menu_StartOver_Click(object sender, RoutedEventArgs e) { var gameDirectory = new DirectoryInfo(Settings.Default.FFXIV_Directory); var index = new Index(gameDirectory); var outdated = false; if (index.IsIndexLocked(XivDataFile._0A_Exd)) { FlexibleMessageBox.Show(UIMessages.IndexLockedErrorMessage, UIMessages.IndexLockedErrorTitle, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } var result = FlexibleMessageBox.Show(UIMessages.StartOverMessage, UIMessages.StartOverTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Information); if (result == System.Windows.Forms.DialogResult.Yes) { var indexBackupsDirectory = new DirectoryInfo(Settings.Default.Backup_Directory); if (!Directory.Exists(indexBackupsDirectory.FullName)) { FlexibleMessageBox.Show(UIMessages.BackupFolderAccessErrorMessage, UIMessages.IndexBackupsErrorTitle, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } var filesToCheck = new XivDataFile[] { XivDataFile._01_Bgcommon, XivDataFile._04_Chara, XivDataFile._06_Ui }; var problemChecker = new ProblemChecker(gameDirectory); foreach (var xivDataFile in filesToCheck) { var backupFile = new DirectoryInfo($"{indexBackupsDirectory.FullName}\\{xivDataFile.GetDataFileName()}.win32.index"); if (!File.Exists(backupFile.FullName)) { continue; } var outdatedCheck = await problemChecker.CheckForOutdatedBackups(xivDataFile, indexBackupsDirectory); if (!outdatedCheck) { FlexibleMessageBox.Show(UIMessages.OutdatedBackupsErrorMessage, UIMessages.IndexBackupsErrorTitle, MessageBoxButtons.OK, MessageBoxIcon.Error); outdated = true; } } await Task.Run(async() => { var modding = new Modding(gameDirectory); await modding.DeleteAllFilesAddedByTexTools(); var dat = new Dat(gameDirectory); var modListDirectory = new DirectoryInfo(Path.Combine(gameDirectory.Parent.Parent.FullName, XivStrings.ModlistFilePath)); var backupFiles = Directory.GetFiles(indexBackupsDirectory.FullName); // Make sure backups exist if (backupFiles.Length == 0) { FlexibleMessageBox.Show(string.Format(UIMessages.NoBackupsFoundErrorMessage, indexBackupsDirectory.FullName), UIMessages.BackupFilesMissingTitle, MessageBoxButtons.OK, MessageBoxIcon.Warning); // Toggle off all mods await modding.ToggleAllMods(false); } else if (outdated) { // Toggle off all mods await modding.ToggleAllMods(false); } else { // Copy backups to ffxiv folder foreach (var backupFile in backupFiles) { if (backupFile.Contains(".win32.index")) { File.Copy(backupFile, $"{gameDirectory}/{Path.GetFileName(backupFile)}", true); } } } // Delete modded dat files foreach (var xivDataFile in (XivDataFile[])Enum.GetValues(typeof(XivDataFile))) { var datFiles = await dat.GetModdedDatList(xivDataFile); foreach (var datFile in datFiles) { File.Delete(datFile); } if (datFiles.Count > 0) { await problemChecker.RepairIndexDatCounts(xivDataFile); } } // Delete mod list File.Delete(modListDirectory.FullName); modding.CreateModlist(); }); UpdateViews(ItemTreeView.SelectedItem as Category); await this.ShowMessageAsync(UIMessages.StartOverCompleteTitle, UIMessages.StartOverCompleteMessage); } }
/// <summary> /// Event handler for the start over menu item clicked /// </summary> private async void Menu_StartOver_Click(object sender, RoutedEventArgs e) { var gameDirectory = new DirectoryInfo(Settings.Default.FFXIV_Directory); var index = new Index(gameDirectory); if (index.IsIndexLocked(XivDataFile._0A_Exd)) { FlexibleMessageBox.Show("Error Accessing Index File\n\n" + "Please exit the game before proceeding.\n" + "-----------------------------------------------------\n\n", "Index Access Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } var result = FlexibleMessageBox.Show("Starting over will:\n\n" + "Restore index files to their original state.\n" + "Delete all mod dat files from game folder.\n" + "Delete all mod list file entries.\n\n" + "Do you want to start over?", "Start Over", MessageBoxButtons.YesNo, MessageBoxIcon.Information); if (result == System.Windows.Forms.DialogResult.Yes) { var task = Task.Run((() => { var modding = new Modding(gameDirectory); var dat = new Dat(gameDirectory); var indexBackupsDirectory = new DirectoryInfo(Settings.Default.Backup_Directory); var modListDirectory = new DirectoryInfo(Path.Combine(gameDirectory.Parent.Parent.FullName, XivStrings.ModlistFilePath)); var backupFiles = Directory.GetFiles(indexBackupsDirectory.FullName); // Make sure backups exist if (backupFiles.Length == 0) { FlexibleMessageBox.Show($"No backup files found in the following directory:\n{indexBackupsDirectory.FullName}\n\n" + $"Index entries will be put back to original offsets instead.\n" + "-----------------------------------------------------\n\n", "Backup Files Missing", MessageBoxButtons.OK, MessageBoxIcon.Warning); // Toggle off all mods modding.ToggleAllMods(false); } else { // Copy backups to ffxiv folder foreach (var backupFile in backupFiles) { if (backupFile.Contains(".win32.index")) { File.Copy(backupFile, $"{gameDirectory}/{Path.GetFileName(backupFile)}", true); } } } // Delete modded dat files foreach (var xivDataFile in (XivDataFile[])Enum.GetValues(typeof(XivDataFile))) { var datFiles = dat.GetModdedDatList(xivDataFile); foreach (var datFile in datFiles) { File.Delete(datFile); } } // Delete mod list File.Delete(modListDirectory.FullName); modding.CreateModlist(); })); task.Wait(); await this.ShowMessageAsync("Start Over Complete", "The start over process has been completed."); } }