/// <summary> /// Gets the metadata file for a given root. /// </summary> /// <param name="root"></param> /// <returns></returns> public static async Task <ItemMetadata> GetMetadata(XivDependencyRoot root, bool forceDefault = false) { if (root == null) { return(null); } Mod mod = null; var filePath = root.Info.GetRootFile(); if (!forceDefault) { var _modding = new Modding(XivCache.GameInfo.GameDirectory); mod = await _modding.TryGetModEntry(filePath); } if (mod != null && mod.enabled) { var _dat = new Dat(XivCache.GameInfo.GameDirectory); // We have modded metadata stored in the .meta file in the DAT we can use. var data = await _dat.GetType2Data(filePath, false); // Run it through the binary deserializer and we're good. //return await Deserialize(data); return(await CreateFromRaw(root, forceDefault)); } else { // This is the fun part where we get to pull the Metadata from all the disparate files around the FFXIV File System. return(await CreateFromRaw(root, forceDefault)); } }
/// <summary> /// Event handler for mod delete button /// </summary> private void modDeleteButton_Click(object sender, RoutedEventArgs e) { var gameDirectory = new DirectoryInfo(Properties.Settings.Default.FFXIV_Directory); var modding = new Modding(gameDirectory); if ((ModListTreeView.SelectedItem as Category).ParentCategory.Name.Equals("ModPacks")) { if (FlexibleMessageBox.Show( "Caution: This will delete all the mods for the currently selected Mod Pack.\n\nThis process is not reversible, do you want to continue?", "Mod Pack Deletion Warning.", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == System.Windows.Forms.DialogResult.Yes) { modding.DeleteModPack((ModListTreeView.SelectedItem as Category).Name); (DataContext as ModListViewModel).RemoveModPack(); } } else { var enumerable = ModItemList.SelectedItems as IEnumerable; var selectedItems = enumerable.OfType <ModListViewModel.ModListModel>().ToArray(); foreach (var selectedModItem in selectedItems) { modding.DeleteMod(selectedModItem.ModItem.fullPath); (DataContext as ModListViewModel).RemoveItem(selectedModItem, (Category)ModListTreeView.SelectedItem); } } }
/// <summary> /// Event handler for mod toggle button changed /// </summary> private async void modToggleButton_Click(object sender, RoutedEventArgs e) { var gameDirectory = new DirectoryInfo(Properties.Settings.Default.FFXIV_Directory); var modding = new Modding(gameDirectory); if ((ModListTreeView.SelectedItem as Category).ParentCategory.Name.Equals("ModPacks")) { var selectedItem = (ModListTreeView.SelectedItem as Category); if ((DataContext as ModListViewModel).ModToggleText == FFXIV_TexTools.Resources.UIStrings.Enable) { await modding.ToggleModPackStatus(selectedItem.Name, true); (DataContext as ModListViewModel).ModToggleText = FFXIV_TexTools.Resources.UIStrings.Disable; } else { await modding.ToggleModPackStatus(selectedItem.Name, false); (DataContext as ModListViewModel).ModToggleText = FFXIV_TexTools.Resources.UIStrings.Enable; } (DataContext as ModListViewModel).UpdateInfoGrid(selectedItem); } else { foreach (ModListViewModel.ModListModel selectedModItem in ModItemList.SelectedItems) { // If mod offset is equal to original offset there is no point in toggling as is the case for matadd textures if (selectedModItem.ModItem.data.modOffset == selectedModItem.ModItem.data.originalOffset) { continue; } if (selectedModItem.ModItem.enabled) { await modding.ToggleModStatus(selectedModItem.ModItem.fullPath, false); (DataContext as ModListViewModel).ModToggleText = FFXIV_TexTools.Resources.UIStrings.Enable; selectedModItem.ActiveBorder = Brushes.Red; selectedModItem.Active = Brushes.Gray; selectedModItem.ActiveOpacity = 0.5f; selectedModItem.ModItem.enabled = false; } else { await modding.ToggleModStatus(selectedModItem.ModItem.fullPath, true); (DataContext as ModListViewModel).ModToggleText = FFXIV_TexTools.Resources.UIStrings.Disable; selectedModItem.ActiveBorder = Brushes.Green; selectedModItem.Active = Brushes.Transparent; selectedModItem.ActiveOpacity = 1; selectedModItem.ModItem.enabled = true; } } } }
/// <summary> /// Saves this metadata file to the FFXIV file system. /// </summary> /// <param name="meta"></param> /// <returns></returns> public static async Task SaveMetadata(ItemMetadata meta, string source, IndexFile index = null, ModList modlist = null) { var _dat = new Dat(XivCache.GameInfo.GameDirectory); var _modding = new Modding(XivCache.GameInfo.GameDirectory); var path = meta.Root.Info.GetRootFile(); var item = meta.Root.GetFirstItem(); await _dat.ImportType2Data(await Serialize(meta), path, source, item, index, modlist); }
/// <summary> /// Creates the simple mod pack data list /// </summary> /// <returns>Task</returns> private async Task MakeSimpleDataList() { DirectoryInfo modListDirectory = new DirectoryInfo(Path.Combine(_gameDirectory.Parent.Parent.FullName, XivStrings.ModlistFilePath)); Modding modding = new Modding(_gameDirectory); this.ModList = modding.GetModList(); // Don't show or list internal mods at all in this menu. this.ModList.Mods.RemoveAll(x => x.IsInternal()); // Rip through the mod list and get the correct raw compressed sizes for all the mods. var _dat = new Dat(XivCache.GameInfo.GameDirectory); foreach (var mod in ModList.Mods) { var compressedSize = mod.data.modSize; try { compressedSize = await _dat.GetCompressedFileSize(mod.data.modOffset, IOUtil.GetDataFileFromPath(mod.fullPath)); mod.data.modSize = compressedSize; } catch { // If the calculation failed, just use the original size I guess? // The main way this happens though is if the data is broken, so maybe we should error? // Though there's possibly filetypes from other framework applications in here that we don't know how to measure? } } this.ParentsDictionary = XivCache.GetModListParents(); List <SimpleModpackEntry> entries = new List <SimpleModpackEntry>(); for (int i = 0; i < this.ModList.Mods.Count; i++) { SimpleModpackEntry entry = MakeEntry(i); if (entry == null) { continue; } entries.Add(entry); } await System.Windows.Application.Current.Dispatcher.InvokeAsync(() => { foreach (SimpleModpackEntry entry in entries) { this.Entries.Add(entry); } }); }
/// <summary> /// Creates the simple mod pack data list /// </summary> /// <returns>Task</returns> private async Task MakeSimpleDataList() { var modListDirectory = new DirectoryInfo(Path.Combine(_gameDirectory.Parent.Parent.FullName, XivStrings.ModlistFilePath)); var modding = new Modding(_gameDirectory); var modList = JsonConvert.DeserializeObject <ModList>(File.ReadAllText(modListDirectory.FullName)); var tasks = modList.Mods.Select(mod => AddToList(mod, modding)); await Task.WhenAll(tasks); }
/// <summary> /// Imports a first generation mod pack /// </summary> /// <param name="modPackDirectory">The mod pack directory</param> private void ImportOldModPack() { var modding = new Modding(_gameDirectory); var originalModPackData = _texToolsModPack.GetOriginalModPackJsonData(_modPackDirectory); foreach (var modsJson in originalModPackData) { var race = GetRace(modsJson.FullPath); var number = GetNumber(modsJson.FullPath); var type = GetType(modsJson.FullPath); var map = GetMap(modsJson.FullPath); var active = false; var isActive = modding.IsModEnabled(modsJson.FullPath, false); if (isActive == XivModStatus.Enabled) { active = true; } _simpleDataList.Add(new SimpleModPackEntries { Name = modsJson.Name, Category = modsJson.Category, Race = race.ToString(), Part = type, Num = number, Map = map, Active = active, JsonEntry = new ModsJson { Name = modsJson.Name, Category = modsJson.Category, FullPath = modsJson.FullPath, DatFile = modsJson.DatFile, ModOffset = modsJson.ModOffset, ModSize = modsJson.ModSize } }); } ModPackName.Content = "N/A"; ModPackAuthor.Content = "N/A"; ModPackVersion.Content = "N/A"; _simpleDataList.Sort(); ModListView.ItemsSource = new ObservableCollection <SimpleModPackEntries>(_simpleDataList); ModListView.SelectAll(); }
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"); } }
public SimpleModPackCreator() { InitializeComponent(); _gameDirectory = new DirectoryInfo(Properties.Settings.Default.FFXIV_Directory); var modListDirectory = new DirectoryInfo(Path.Combine(_gameDirectory.Parent.Parent.FullName, XivStrings.ModlistFilePath)); var modding = new Modding(_gameDirectory); var modList = JsonConvert.DeserializeObject <ModList>(File.ReadAllText(modListDirectory.FullName)); foreach (var mod in modList.Mods) { if (mod.fullPath.Equals(string.Empty)) { continue; } var race = GetRace(mod.fullPath); var number = GetNumber(mod.fullPath); var type = GetType(mod.fullPath); var map = GetMap(mod.fullPath); var active = false; var isActive = modding.IsModEnabled(mod.fullPath, false); if (isActive == XivModStatus.Enabled) { active = true; } _simpleDataList.Add(new SimpleModPackEntries { Name = mod.name, Category = mod.category, Race = race.ToString(), Part = type, Num = number, Map = map, Active = active, ModEntry = mod }); } _simpleDataList.Sort(); ModListView.ItemsSource = new ObservableCollection <SimpleModPackEntries>(_simpleDataList); }
/// <summary> /// Imports a simple mod pack /// </summary> /// <param name="modPackJson">The mod pack json</param> private void ImportSimpleModPack(ModPackJson modPackJson) { var modding = new Modding(_gameDirectory); foreach (var modsJson in modPackJson.SimpleModsList) { var race = GetRace(modsJson.FullPath); var number = GetNumber(modsJson.FullPath); var type = GetType(modsJson.FullPath); var map = GetMap(modsJson.FullPath); var active = false; var isActive = modding.IsModEnabled(modsJson.FullPath, false); if (isActive == XivModStatus.Enabled) { active = true; } modsJson.ModPackEntry = new ModPack { name = modPackJson.Name, author = modPackJson.Author, version = modPackJson.Version }; _simpleDataList.Add(new SimpleModPackEntries { Name = modsJson.Name, Category = modsJson.Category, Race = race.ToString(), Part = type, Num = number, Map = map, Active = active, JsonEntry = modsJson, }); } ModPackName.Content = modPackJson.Name; ModPackAuthor.Content = modPackJson.Author; ModPackVersion.Content = modPackJson.Version; _simpleDataList.Sort(); ModListView.ItemsSource = new ObservableCollection <SimpleModPackEntries>(_simpleDataList); ModListView.SelectAll(); }
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); } }
/// <summary> /// Event handler for mod toggle button changed /// </summary> private void modToggleButton_Click(object sender, RoutedEventArgs e) { var gameDirectory = new DirectoryInfo(Properties.Settings.Default.FFXIV_Directory); var modding = new Modding(gameDirectory); if ((ModListTreeView.SelectedItem as Category).ParentCategory.Name.Equals("ModPacks")) { var selectedItem = (ModListTreeView.SelectedItem as Category); if ((DataContext as ModListViewModel).ModToggleText == "Enable") { modding.ToggleModPackStatus(selectedItem.Name, true); (DataContext as ModListViewModel).ModToggleText = "Disable"; } else { modding.ToggleModPackStatus(selectedItem.Name, false); (DataContext as ModListViewModel).ModToggleText = "Enable"; } (DataContext as ModListViewModel).UpdateInfoGrid(selectedItem); } else { foreach (ModListViewModel.ModListModel selectedModItem in ModItemList.SelectedItems) { if (selectedModItem.ModItem.enabled) { modding.ToggleModStatus(selectedModItem.ModItem.fullPath, false); (DataContext as ModListViewModel).ModToggleText = "Enable"; selectedModItem.ActiveBorder = Brushes.Red; selectedModItem.Active = Brushes.Gray; selectedModItem.ActiveOpacity = 0.5f; selectedModItem.ModItem.enabled = false; } else { modding.ToggleModStatus(selectedModItem.ModItem.fullPath, true); (DataContext as ModListViewModel).ModToggleText = "Disable"; selectedModItem.ActiveBorder = Brushes.Green; selectedModItem.Active = Brushes.Transparent; selectedModItem.ActiveOpacity = 1; selectedModItem.ModItem.enabled = true; } } } }
/// <summary> /// Imports a simple mod pack /// </summary> /// <param name="modPackJson">The mod pack json</param> private async Task ImportSimpleModPack(ModPackJson modPackJson) { var modding = new Modding(_gameDirectory); var tasks = modPackJson.SimpleModsList.Select(modsJson => AddToList(modsJson, modding, modPackJson)); await Task.WhenAll(tasks); ModPackName.Content = modPackJson.Name; ModPackAuthor.Content = modPackJson.Author; ModPackVersion.Content = modPackJson.Version; var cv = (CollectionView)CollectionViewSource.GetDefaultView(ModListView.ItemsSource); cv.SortDescriptions.Clear(); cv.SortDescriptions.Add(new SortDescription(nameof(SimpleModPackEntries.Name), _lastDirection)); ModListView.SelectAll(); }
/// <summary> /// Event handler for mod delete button /// </summary> private async void modDeleteButton_Click(object sender, RoutedEventArgs e) { var gameDirectory = new DirectoryInfo(Properties.Settings.Default.FFXIV_Directory); var modding = new Modding(gameDirectory); await LockUi("Deleting Mod", "Please wait...", this); try { if ((ModListTreeView.SelectedItem as Category).ParentCategory.Name.Equals("ModPacks")) { if (FlexibleMessageBox.Show( UIMessages.DeleteModPackMessage, UIMessages.DeleteModPackTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == System.Windows.Forms.DialogResult.Yes) { await modding.DeleteModPack((ModListTreeView.SelectedItem as Category).Name); (DataContext as ModListViewModel).RemoveModPack(); } } else { var enumerable = ModItemList.SelectedItems as IEnumerable; var selectedItems = enumerable.OfType <ModListViewModel.ModListModel>().ToArray(); foreach (var selectedModItem in selectedItems) { await modding.DeleteMod(selectedModItem.ModItem.fullPath); (DataContext as ModListViewModel).RemoveItem(selectedModItem, (Category)ModListTreeView.SelectedItem); } } } catch (Exception Ex) { FlexibleMessageBox.Show("Unable to delete Mod or Modpack.\n\nError: " + Ex.Message, "Mod Delete Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } finally { await UnlockUi(this); } }
/// <summary> /// Disables the .rgsp file for this race, if it exists, and restores the .cmp file for the race back to default. /// </summary> /// <param name="race"></param> /// <param name="gender"></param> /// <returns></returns> public static async Task DisableRgspMod(XivSubRace race, XivGender gender) { var path = GetRgspPath(race, gender); var _modding = new Modding(XivCache.GameInfo.GameDirectory); var modlist = await _modding.GetModListAsync(); var mod = modlist.Mods.FirstOrDefault(x => x.fullPath == path); if (mod != null && mod.enabled) { await _modding.ToggleModStatus(path, false); } else { var def = await GetScalingParameter(race, gender, true); await SetScalingParameter(def); } }
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 async void ToggleButton_Click(object sender, RoutedEventArgs e) { var _modding = new Modding(XivCache.GameInfo.GameDirectory); var path = _root.Info.GetRootFile(); var mod = await _modding.TryGetModEntry(path); if (mod == null) { return; } var enabled = mod.enabled; await MainWindow.GetMainWindow().LockUi("Updating Metadata"); try { if (enabled) { await _modding.ToggleModStatus(path, false); ToggleButton.Content = "Enable"; } else { await _modding.ToggleModStatus(path, true); ToggleButton.Content = "Disable"; } } catch (Exception ex) { FlexibleMessageBox.Show("Unable to toggle mod status.\n\nError: " + ex.Message, "Mod Toggle Error", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error); } finally { await MainWindow.GetMainWindow().UnlockUi(); var mw = MainWindow.GetMainWindow(); mw.ReloadItem(); } }
/// <summary> /// Gets the model info from the modelchara exd file /// </summary> /// <param name="gameDirectory">The game directory</param> /// <param name="index">The index of the data</param> /// <returns>The XivModelInfo data</returns> public static async Task <XivModelInfo> GetModelInfo(Modding modding, int index) { var xivModelInfo = new XivModelInfo(); // These are the offsets to relevant data // These will need to be changed if data gets added or removed with a patch const int modelDataOffset = 4; var ex = new Ex(modding); var modelCharaEx = await ex.ReadExData(XivEx.modelchara); // Big Endian Byte Order using (var br = new BinaryReaderBE(new MemoryStream(modelCharaEx[index]))) { xivModelInfo.ModelID = br.ReadInt16(); br.BaseStream.Seek(modelDataOffset, SeekOrigin.Begin); var modelType = br.ReadByte(); xivModelInfo.Body = br.ReadByte(); xivModelInfo.Variant = br.ReadByte(); if (modelType == 2) { xivModelInfo.ModelType = XivItemType.demihuman; } else if (modelType == 3) { xivModelInfo.ModelType = XivItemType.monster; } else { xivModelInfo.ModelType = XivItemType.unknown; } } return(xivModelInfo); }
public BackupModPackCreator() { InitializeComponent(); _gameDirectory = new DirectoryInfo(Properties.Settings.Default.FFXIV_Directory); var modding = new Modding(_gameDirectory); _modList = modding.GetModList(); DataContext = new BackupModpackViewModel(); ModpackList.ItemsSource = new List <BackupModpackItemEntry>(); ModPackName.Text = string.Format("Backup_{0}", DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss")); // Manually add an entry for the mods that don't belong to a modpack ((List <BackupModpackItemEntry>)ModpackList.ItemsSource).Add(new BackupModpackItemEntry(UIStrings.Standalone_Non_ModPack)); foreach (var modpack in _modList.ModPacks) { var entry = new BackupModpackItemEntry(modpack.name); ((List <BackupModpackItemEntry>)ModpackList.ItemsSource).Add(entry); } ModpackList.SelectedIndex = 0; }
/// <summary> /// Asks for game directory and sets default save directory /// </summary> private void SetDirectories(bool valid) { if (valid) { var resourceManager = CommonInstallDirectories.ResourceManager; var resourceSet = resourceManager.GetResourceSet(CultureInfo.CurrentCulture, true, true); if (Properties.Settings.Default.FFXIV_Directory.Equals("")) { var saveDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "/TexTools/Saved"; Directory.CreateDirectory(saveDirectory); Properties.Settings.Default.Save_Directory = saveDirectory; Properties.Settings.Default.Save(); var installDirectory = ""; foreach (DictionaryEntry commonInstallPath in resourceSet) { if (!Directory.Exists(commonInstallPath.Value.ToString())) { continue; } if (FlexibleMessageBox.Show("FFXIV install directory found at \n\n" + commonInstallPath.Value + "\n\nUse this directory? ", "Install Directory Found", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) { installDirectory = commonInstallPath.Value.ToString(); Properties.Settings.Default.FFXIV_Directory = installDirectory; Properties.Settings.Default.Save(); break; } } if (string.IsNullOrEmpty(installDirectory)) { if (FlexibleMessageBox.Show("Please locate the following directory. \n\n .../FINAL FANTASY XIV - A Realm Reborn/game/sqpack/ffxiv", "Install Directory Not Found", MessageBoxButtons.OK, MessageBoxIcon.Question) == DialogResult.OK) { while (!installDirectory.Contains("ffxiv")) { var folderSelect = new FolderSelectDialog() { Title = "Select sqpack/ffxiv Folder" }; var result = folderSelect.ShowDialog(); if (result) { installDirectory = folderSelect.FileName; } else { Environment.Exit(0); } } Properties.Settings.Default.FFXIV_Directory = installDirectory; Properties.Settings.Default.Save(); } else { Environment.Exit(0); } } } // Check if it is an old Directory var fileLastModifiedTime = File.GetLastWriteTime( $"{Properties.Settings.Default.FFXIV_Directory}\\{XivDataFile._0A_Exd.GetDataFileName()}.win32.dat0"); if (fileLastModifiedTime.Year < 2019) { SetDirectories(false); } SetSaveDirectory(); SetBackupsDirectory(); SetModPackDirectory(); var modding = new Modding(new DirectoryInfo(Properties.Settings.Default.FFXIV_Directory)); modding.CreateModlist(); } else { if (FlexibleMessageBox.Show("The install location chosen is out of date \n\nPlease locate the following directory. \n\n " + ".../FINAL FANTASY XIV - A Realm Reborn/game/sqpack/ffxiv", "Install Directory Not Found", MessageBoxButtons.OK, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.OK) { var installDirectory = ""; while (!installDirectory.Contains("ffxiv")) { var folderSelect = new FolderSelectDialog() { Title = "Select sqpack/ffxiv Folder" }; var result = folderSelect.ShowDialog(); if (result) { installDirectory = folderSelect.FileName; } else { Environment.Exit(0); } } // Check if it is an old Directory var fileLastModifiedTime = File.GetLastWriteTime( $"{installDirectory}\\{XivDataFile._0A_Exd.GetDataFileName()}.win32.dat0"); if (fileLastModifiedTime.Year < 2019) { SetDirectories(false); } else { Properties.Settings.Default.FFXIV_Directory = installDirectory; Properties.Settings.Default.Save(); } } else { Environment.Exit(0); } } }
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(); } } })); }
/// <summary> /// Asks for game directory and sets default save directory /// </summary> private void SetDirectories(bool valid) { if (valid) { var resourceManager = CommonInstallDirectories.ResourceManager; var resourceSet = resourceManager.GetResourceSet(CultureInfo.CurrentCulture, true, true); if (Properties.Settings.Default.FFXIV_Directory.Equals("")) { var saveDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "/TexTools/Saved"; Directory.CreateDirectory(saveDirectory); Properties.Settings.Default.Save_Directory = saveDirectory; Properties.Settings.Default.Save(); var installDirectory = ""; foreach (DictionaryEntry commonInstallPath in resourceSet) { if (!Directory.Exists(commonInstallPath.Value.ToString())) { continue; } if (FlexibleMessageBox.Show(string.Format(UIMessages.InstallDirectoryFoundMessage, commonInstallPath.Value), UIMessages.InstallDirectoryFoundTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) { installDirectory = commonInstallPath.Value.ToString(); Properties.Settings.Default.FFXIV_Directory = installDirectory; Properties.Settings.Default.Save(); break; } } if (string.IsNullOrEmpty(installDirectory)) { if (FlexibleMessageBox.Show(UIMessages.InstallDirectoryNotFoundMessage, UIMessages.InstallDirectoryNotFoundTitle, MessageBoxButtons.OK, MessageBoxIcon.Question) == DialogResult.OK) { while (!installDirectory.Contains("ffxiv")) { var folderSelect = new FolderSelectDialog() { Title = UIMessages.SelectffxivFolderTitle }; var result = folderSelect.ShowDialog(); if (result) { installDirectory = folderSelect.FileName; } else { Environment.Exit(0); } } Properties.Settings.Default.FFXIV_Directory = installDirectory; Properties.Settings.Default.Save(); } else { Environment.Exit(0); } } } // Check if it is an old Directory var fileLastModifiedTime = File.GetLastWriteTime( $"{Properties.Settings.Default.FFXIV_Directory}\\{XivDataFile._0A_Exd.GetDataFileName()}.win32.dat0"); if (fileLastModifiedTime.Year < 2019) { SetDirectories(false); } SetSaveDirectory(); SetBackupsDirectory(); SetModPackDirectory(); var modding = new Modding(new DirectoryInfo(Properties.Settings.Default.FFXIV_Directory)); modding.CreateModlist(); } else { if (FlexibleMessageBox.Show(UIMessages.OutOfDateInstallMessage, UIMessages.OutOfDateInstallTitle, MessageBoxButtons.OK, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.OK) { var installDirectory = ""; while (!installDirectory.Contains("ffxiv")) { var folderSelect = new FolderSelectDialog() { Title = UIMessages.SelectffxivFolderTitle }; var result = folderSelect.ShowDialog(); if (result) { installDirectory = folderSelect.FileName; } else { Environment.Exit(0); } } // Check if it is an old Directory var fileLastModifiedTime = File.GetLastWriteTime( $"{installDirectory}\\{XivDataFile._0A_Exd.GetDataFileName()}.win32.dat0"); if (fileLastModifiedTime.Year < 2019) { SetDirectories(false); } else { Properties.Settings.Default.FFXIV_Directory = installDirectory; Properties.Settings.Default.Save(); } } else { Environment.Exit(0); } } }
/// <summary> /// Checks for older modlist /// </summary> private async void CheckForOldModList() { var oldModListFileDirectory = new DirectoryInfo( $"{Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)}/TexTools/TexTools.modlist"); if (File.Exists(oldModListFileDirectory.FullName)) { var modListContent = File.ReadAllLines(oldModListFileDirectory.FullName); if (modListContent.Length > 0) { if (FlexibleMessageBox.Show(_win32Window, UIMessages.OldTexToolsFoundMessage, UIMessages.OldModListFoundTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) { var modding = new Modding(_gameDirectory); var dat = new Dat(_gameDirectory); var error = false; if (_index.IsIndexLocked(XivDataFile._0A_Exd)) { FlexibleMessageBox.Show(_win32Window, UIMessages.ModListIndexLockedErrorMessage, UIMessages.ModListDisableFailedTitle, MessageBoxButtons.OK, MessageBoxIcon.Warning); error = true; } else { try { await modding.DisableOldModList(oldModListFileDirectory); } catch (Exception ex) { error = true; FlexibleMessageBox.Show(_win32Window, string.Format(UIMessages.OldModListDisableFailedMessage, ex.Message), UIMessages.PreviousVersionErrorTitle, MessageBoxButtons.OK, MessageBoxIcon.Error); } } if (!error) { File.Delete(oldModListFileDirectory.FullName); // 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); } } } else { System.Windows.Application.Current.Shutdown(); } } else { System.Windows.Application.Current.Shutdown(); } } } }
public Imc(Modding modding, XivDataFile dataFile) { _modding = modding; _dataFile = dataFile; }
private async Task CreateBasic() { string modPackPath = Path.Combine(Properties.Settings.Default.ModPack_Directory, $"{ViewModel.Name}.ttmp2"); if (File.Exists(modPackPath)) { DialogResult overwriteDialogResult = FlexibleMessageBox.Show(new Wpf32Window(this), UIMessages.ModPackOverwriteMessage, UIMessages.OverwriteTitle, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning); if (overwriteDialogResult != System.Windows.Forms.DialogResult.Yes) { return; } } TTMP texToolsModPack = new TTMP(new DirectoryInfo(Settings.Default.ModPack_Directory), XivStrings.TexTools); var index = new Index(XivCache.GameInfo.GameDirectory); var dat = new Dat(XivCache.GameInfo.GameDirectory); var modding = new Modding(XivCache.GameInfo.GameDirectory); var ModList = modding.GetModList(); SimpleModPackData simpleModPackData = new SimpleModPackData { Name = ViewModel.Name, Author = ViewModel.Author, Version = ViewModel.Version, Description = ViewModel.Description, Url = ViewModel.Url, SimpleModDataList = new List <SimpleModData>() }; foreach (var entry in ViewModel.Entries) { foreach (var file in entry.AllFiles) { var exists = await index.FileExists(file); // This is a funny case where in order to create the modpack we actually have to write a default meta entry to the dats first. // If we had the right functions we could just load and serialize the data, but we don't atm. if (!exists && Path.GetExtension(file) == ".meta") { var meta = await ItemMetadata.GetMetadata(file); await ItemMetadata.SaveMetadata(meta, XivStrings.TexTools); } var offset = await index.GetDataOffset(file); var dataFile = IOUtil.GetDataFileFromPath(file); var compressedSize = await dat.GetCompressedFileSize(offset, dataFile); var modEntry = ModList.Mods.FirstOrDefault(x => x.fullPath == file); var modded = modEntry != null && modEntry.enabled == true; SimpleModData simpleData = new SimpleModData { Name = entry.Item.Name, Category = entry.Item.SecondaryCategory, FullPath = file, ModOffset = offset, ModSize = compressedSize, IsDefault = !modded, DatFile = dataFile.GetDataFileName() }; simpleModPackData.SimpleModDataList.Add(simpleData); } } try { await LockUi(UIStrings.Creating_Modpack, null, null); Progress <(int current, int total, string message)> progressIndicator = new Progress <(int current, int total, string message)>(ReportProgress); await texToolsModPack.CreateSimpleModPack(simpleModPackData, XivCache.GameInfo.GameDirectory, progressIndicator, true); FlexibleMessageBox.Show(new Wpf32Window(this), "Modpack Created Successfully.", "Modpack Created", MessageBoxButtons.OK, MessageBoxIcon.Information); await UnlockUi(this); DialogResult = true; } catch (Exception ex) { FlexibleMessageBox.Show(new Wpf32Window(this), "An Error occured while creating the modpack.\n\n" + ex.Message, "Modpack Creation Error", MessageBoxButtons.OK, MessageBoxIcon.Error); await UnlockUi(this); } }
private async Task CreateAdvanced() { string modPackPath = Path.Combine(Properties.Settings.Default.ModPack_Directory, $"{ViewModel.Name}.ttmp2"); if (File.Exists(modPackPath)) { DialogResult overwriteDialogResult = FlexibleMessageBox.Show(new Wpf32Window(this), UIMessages.ModPackOverwriteMessage, UIMessages.OverwriteTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Warning); if (overwriteDialogResult != System.Windows.Forms.DialogResult.Yes) { return; } } await LockUi(UIStrings.Creating_Modpack, null, null); try { TTMP texToolsModPack = new TTMP(new DirectoryInfo(Settings.Default.ModPack_Directory), XivStrings.TexTools); var index = new Index(XivCache.GameInfo.GameDirectory); var dat = new Dat(XivCache.GameInfo.GameDirectory); var modding = new Modding(XivCache.GameInfo.GameDirectory); var ModList = modding.GetModList(); var wizardData = new ModPackData() { Name = ViewModel.Name, Author = ViewModel.Author, Version = ViewModel.Version, Description = ViewModel.Description, Url = ViewModel.Url, ModPackPages = new List <ModPackData.ModPackPage>() }; var page = new ModPackData.ModPackPage() { PageIndex = 1, ModGroups = new List <ModGroup>() }; wizardData.ModPackPages.Add(page); foreach (var e in ViewModel.Entries) { var item = e.Item; var files = e.AllFiles; var group = new ModGroup() { GroupName = item.Name, SelectionType = "Multi", OptionList = new List <ModOption>() }; page.ModGroups.Add(group); var option = new ModOption { GroupName = group.GroupName, IsChecked = true, Name = GetNiceLevelName(e.Level, true, true), Description = "Item: " + item.Name + "\nInclusion Level: " + GetNiceLevelName(e.Level) + "\nPrimary Files:" + e.MainFiles.Count + "\nTotal Files:" + e.AllFiles.Count, SelectionType = "Multi", }; group.OptionList.Add(option); foreach (var file in e.AllFiles) { var exists = await index.FileExists(file); // This is a funny case where in order to create the modpack we actually have to write a default meta entry to the dats first. // If we had the right functions we could just load and serialize the data, but we don't atm. if (!exists && Path.GetExtension(file) == ".meta") { var meta = await ItemMetadata.GetMetadata(file); await ItemMetadata.SaveMetadata(meta, XivStrings.TexTools); } var offset = await index.GetDataOffset(file); var dataFile = IOUtil.GetDataFileFromPath(file); var compressedSize = await dat.GetCompressedFileSize(offset, dataFile); var modEntry = ModList.Mods.FirstOrDefault(x => x.fullPath == file); var modded = modEntry != null && modEntry.enabled == true; var fData = new ModData { Name = e.Item.Name, Category = e.Item.SecondaryCategory, FullPath = file, IsDefault = !modded, ModDataBytes = dat.GetRawData(offset, dataFile, compressedSize) }; option.Mods.Add(file, fData); } } // Okay modpack is now created internally, just need to save it. var progressIndicator = new Progress <double>(ReportProgressAdv); await texToolsModPack.CreateWizardModPack(wizardData, progressIndicator, true); FlexibleMessageBox.Show(new Wpf32Window(this), "Modpack Created Successfully.", "Modpack Created", MessageBoxButtons.OK, MessageBoxIcon.Information); await UnlockUi(this); DialogResult = true; } catch (Exception ex) { FlexibleMessageBox.Show(new Wpf32Window(this), "An Error occured while creating the modpack.\n\n" + ex.Message, "Modpack Creation Error", MessageBoxButtons.OK, MessageBoxIcon.Error); await UnlockUi(this); } }
public async Task <int> TexBMPImporter(XivTex xivTex, IItem item, DirectoryInfo bmpFileDirectory, string source) { var offset = 0; var modding = new Modding(_gameDirectory); if (File.Exists(bmpFileDirectory.FullName)) { // Check if the texture being imported has been imported before var modEntry = await modding.TryGetModEntry(xivTex.TextureTypeAndPath.Path); var ddsContainer = new DDSContainer(); CompressionFormat compressionFormat; switch (xivTex.TextureFormat) { case XivTexFormat.DXT1: compressionFormat = CompressionFormat.BC1; break; case XivTexFormat.DXT5: compressionFormat = CompressionFormat.BC3; break; case XivTexFormat.A8R8G8B8: compressionFormat = CompressionFormat.BGRA; break; default: throw new Exception($"Format {xivTex.TextureFormat} is not currently supported for BMP import\n\nPlease use the DDS import option instead."); } using (var surface = Surface.LoadFromFile(bmpFileDirectory.FullName)) { surface.FlipVertically(); using (var compressor = new Compressor()) { compressor.Input.GenerateMipmaps = true; compressor.Input.SetData(surface); compressor.Compression.Format = compressionFormat; compressor.Compression.SetBGRAPixelFormat(); compressor.Process(out ddsContainer); } } using (var ddsMemoryStream = new MemoryStream()) { ddsContainer.Write(ddsMemoryStream, DDSFlags.None); using (var br = new BinaryReader(ddsMemoryStream)) { br.BaseStream.Seek(12, SeekOrigin.Begin); var newHeight = br.ReadInt32(); var newWidth = br.ReadInt32(); br.ReadBytes(8); var newMipCount = br.ReadInt32(); if (newHeight % 2 != 0 || newWidth % 2 != 0) { throw new Exception("Resolution must be a multiple of 2"); } br.BaseStream.Seek(80, SeekOrigin.Begin); var textureFlags = br.ReadInt32(); var texType = br.ReadInt32(); XivTexFormat textureType; if (DDSType.ContainsKey(texType)) { textureType = DDSType[texType]; } else { throw new Exception($"DDS Type ({texType}) not recognized."); } switch (textureFlags) { case 2 when textureType == XivTexFormat.A8R8G8B8: textureType = XivTexFormat.A8; break; case 65 when textureType == XivTexFormat.A8R8G8B8: var bpp = br.ReadInt32(); if (bpp == 32) { textureType = XivTexFormat.A8R8G8B8; } else { var red = br.ReadInt32(); switch (red) { case 31744: textureType = XivTexFormat.A1R5G5B5; break; case 3840: textureType = XivTexFormat.A4R4G4B4; break; } } break; } if (textureType == xivTex.TextureFormat) { var uncompressedLength = ddsMemoryStream.Length; var newTex = new List <byte>(); if (!xivTex.TextureTypeAndPath.Path.Contains(".atex")) { var DDSInfo = await DDS.ReadDDS(br, xivTex, newWidth, newHeight, newMipCount); newTex.AddRange(_dat.MakeType4DatHeader(xivTex, DDSInfo.mipPartOffsets, DDSInfo.mipPartCounts, (int)uncompressedLength, newMipCount, newWidth, newHeight)); newTex.AddRange(MakeTextureInfoHeader(xivTex, newWidth, newHeight, newMipCount)); newTex.AddRange(DDSInfo.compressedDDS); offset = await _dat.WriteToDat(newTex, modEntry, xivTex.TextureTypeAndPath.Path, item.ItemCategory, item.Name, xivTex.TextureTypeAndPath.DataFile, source, 4); } else { br.BaseStream.Seek(128, SeekOrigin.Begin); newTex.AddRange(MakeTextureInfoHeader(xivTex, newWidth, newHeight, newMipCount)); newTex.AddRange(br.ReadBytes((int)uncompressedLength)); offset = await _dat.ImportType2Data(newTex.ToArray(), item.Name, xivTex.TextureTypeAndPath.Path, item.ItemCategory, source); } } else { throw new Exception($"Incorrect file type. Expected: {xivTex.TextureFormat} Given: {textureType}"); } } } ddsContainer.Dispose(); } else { throw new IOException($"Could not find file: {bmpFileDirectory.FullName}"); } return(offset); }
/// <summary> /// Converts a DDS file into a TEX file then imports it /// </summary> /// <param name="xivTex">The texture data</param> /// <param name="item">The item who's texture we are importing</param> /// <param name="ddsFileDirectory">The directory of the dds file being imported</param> /// <returns>The offset to the new imported data</returns> public async Task <int> TexDDSImporter(XivTex xivTex, IItem item, DirectoryInfo ddsFileDirectory, string source) { var offset = 0; var modding = new Modding(_gameDirectory); if (File.Exists(ddsFileDirectory.FullName)) { // Check if the texture being imported has been imported before var modEntry = await modding.TryGetModEntry(xivTex.TextureTypeAndPath.Path); using (var br = new BinaryReader(File.OpenRead(ddsFileDirectory.FullName))) { br.BaseStream.Seek(12, SeekOrigin.Begin); var newHeight = br.ReadInt32(); var newWidth = br.ReadInt32(); br.ReadBytes(8); var newMipCount = br.ReadInt32(); if (newHeight % 2 != 0 || newWidth % 2 != 0) { throw new Exception("Resolution must be a multiple of 2"); } br.BaseStream.Seek(80, SeekOrigin.Begin); var textureFlags = br.ReadInt32(); var texType = br.ReadInt32(); XivTexFormat textureType; if (DDSType.ContainsKey(texType)) { textureType = DDSType[texType]; } else { throw new Exception($"DDS Type ({texType}) not recognized."); } switch (textureFlags) { case 2 when textureType == XivTexFormat.A8R8G8B8: textureType = XivTexFormat.A8; break; case 65 when textureType == XivTexFormat.A8R8G8B8: var bpp = br.ReadInt32(); if (bpp == 32) { textureType = XivTexFormat.A8R8G8B8; } else { var red = br.ReadInt32(); switch (red) { case 31744: textureType = XivTexFormat.A1R5G5B5; break; case 3840: textureType = XivTexFormat.A4R4G4B4; break; } } break; } if (textureType == xivTex.TextureFormat) { var uncompressedLength = (int)new FileInfo(ddsFileDirectory.FullName).Length - 128; var newTex = new List <byte>(); if (!xivTex.TextureTypeAndPath.Path.Contains(".atex")) { var DDSInfo = await DDS.ReadDDS(br, xivTex, newWidth, newHeight, newMipCount); newTex.AddRange(_dat.MakeType4DatHeader(xivTex, DDSInfo.mipPartOffsets, DDSInfo.mipPartCounts, uncompressedLength, newMipCount, newWidth, newHeight)); newTex.AddRange(MakeTextureInfoHeader(xivTex, newWidth, newHeight, newMipCount)); newTex.AddRange(DDSInfo.compressedDDS); offset = await _dat.WriteToDat(newTex, modEntry, xivTex.TextureTypeAndPath.Path, item.ItemCategory, item.Name, xivTex.TextureTypeAndPath.DataFile, source, 4); } else { br.BaseStream.Seek(128, SeekOrigin.Begin); newTex.AddRange(MakeTextureInfoHeader(xivTex, newWidth, newHeight, newMipCount)); newTex.AddRange(br.ReadBytes(uncompressedLength)); offset = await _dat.ImportType2Data(newTex.ToArray(), item.Name, xivTex.TextureTypeAndPath.Path, item.ItemCategory, source); } } else { throw new Exception($"Incorrect file type. Expected: {xivTex.TextureFormat} Given: {textureType}"); } } } else { throw new IOException($"Could not find file: {ddsFileDirectory.FullName}"); } return(offset); }
private void CheckForOldModList() { var oldModListFileDirectory = new DirectoryInfo($"{Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)}/TexTools/TexTools.modlist"); if (File.Exists(oldModListFileDirectory.FullName)) { var modListContent = File.ReadAllLines(oldModListFileDirectory.FullName); if (modListContent.Length > 0) { var warningMessage = "Older TexTools ModList Found.\n\nThe Older ModList is incompatible with this version.\n\nIn order to use this version, all previous mods will be disabled, and the previous ModList erased.\n\n" + "If you would like to retain your mods, it is recommended that you create a backup ModPack in the older TexTools Version, then import it into this one.\n\nWould you like to continue?"; if (FlexibleMessageBox.Show( $"{warningMessage}", "Older ModList Found", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) { var modding = new Modding(_gameDirectory); var index = new Index(_gameDirectory); var dat = new Dat(_gameDirectory); var error = false; if (index.IsIndexLocked(XivDataFile._0A_Exd)) { FlexibleMessageBox.Show("Unable to continue while game is running.\n\nPlease exit the game and try again.", $"ModList Disable Failed", MessageBoxButtons.OK, MessageBoxIcon.Warning); error = true; } else { try { modding.DisableOldModList(oldModListFileDirectory); } catch (Exception ex) { error = true; var message = $"There was an error attempting to disable a mod from previous version.\n\nError Message:\n{ex.Message}\n\nIt is recommended to do a Start Over from the previous version first."; FlexibleMessageBox.Show(message, $"Previous Version Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } if (!error) { File.Delete(oldModListFileDirectory.FullName); // 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); } } } else { System.Windows.Application.Current.Shutdown(); } } else { System.Windows.Application.Current.Shutdown(); } } } }
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); } } } } }