/// <summary> /// Gets the Icon info for a specific gear item /// </summary> /// <param name="gearItem">The gear item</param> /// <returns>A list of TexTypePath containing Icon Info</returns> public async Task <List <TexTypePath> > GetItemIcons(IItemModel iconItem) { var type = iconItem.GetType(); uint iconNumber = 0; if (type == typeof(XivGear)) { iconNumber = ((XivGear)iconItem).IconNumber; } else if (type == typeof(XivFurniture)) { iconNumber = ((XivFurniture)iconItem).IconNumber; } if (iconNumber <= 0) { return(new List <TexTypePath>()); } var iconString = iconNumber.ToString(); var ttpList = new List <TexTypePath>(); var iconBaseNum = iconString.Substring(0, 2).PadRight(iconString.Length, '0'); var iconFolder = $"ui/icon/{iconBaseNum.PadLeft(6, '0')}"; var iconHQFolder = $"{iconFolder}/hq"; var iconFile = $"{iconString.PadLeft(6, '0')}.tex"; var path = iconFolder + "/" + iconFile; if (await _index.FileExists(path, XivDataFile._06_Ui)) { ttpList.Add(new TexTypePath { Name = "Icon", Path = $"{iconFolder}/{iconFile}", Type = XivTexType.Icon, DataFile = XivDataFile._06_Ui }); } path = iconHQFolder + "/" + iconFile; if (await _index.FileExists(path, XivDataFile._06_Ui)) { ttpList.Add(new TexTypePath { Name = "HQ Icon", Path = $"{iconHQFolder}/{iconFile}", Type = XivTexType.Icon, DataFile = XivDataFile._06_Ui }); } return(ttpList); }
private async Task DoCopy() { var from = FromBox.Text; var to = ToBox.Text; if (String.IsNullOrWhiteSpace(to) || String.IsNullOrWhiteSpace(to)) { return; } var _dat = new Dat(XivCache.GameInfo.GameDirectory); var _index = new Index(XivCache.GameInfo.GameDirectory); try { var exists = await _index.FileExists(from); if (!exists) { throw new InvalidDataException("Source file does not exist."); } exists = await _index.FileExists(to); if (exists) { var cancel = false; Dispatcher.Invoke(() => { var result = FlexibleMessageBox.Show("Destination file already exists. Overwrite?", "Overwrite Confirmation", System.Windows.Forms.MessageBoxButtons.YesNo, System.Windows.Forms.MessageBoxIcon.Warning); cancel = result == System.Windows.Forms.DialogResult.No; }); if (cancel) { return; } } await _dat.CopyFile(from, to, XivStrings.TexTools, true); Dispatcher.Invoke(() => { FlexibleMessageBox.Show("File Copied Successfully.", "Copy Success", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Information); Close(); }); } catch (Exception ex) { FlexibleMessageBox.Show("File Copy Failed:\n" + ex.Message, "Copy Failure", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error); } }
private async Task <bool> AddFile(string file) { var _index = new Index(XivCache.GameInfo.GameDirectory); if (Path.GetExtension(file) != ".meta") { if (!(await _index.FileExists(file))) { // File doesn't actually exist, can't be added. return(false); } } var match = _suffixRegex.Match(file); if (match.Success && match.Groups[1].Value == "mdl") { ModelListBox.Items.Add(new StandardModpackFileSelect.FileEntry(file)); } else if (match.Success && (match.Groups[1].Value == "mtrl" || match.Groups[1].Value == "avfx")) { MaterialListBox.Items.Add(new StandardModpackFileSelect.FileEntry(file)); } else if (match.Success && (match.Groups[1].Value == "tex" || match.Groups[1].Value == "atex")) { TextureListBox.Items.Add(new StandardModpackFileSelect.FileEntry(file)); } else { MetaListBox.Items.Add(new StandardModpackFileSelect.FileEntry(file)); } return(true); }
public async Task <char> GetNewMaterialIdentifier() { // Get new Material Identifier var alphabet = Constants.Alphabet; List <string> partList = new List <string>(); var materialIdentifier = _material.GetMaterialIdentifier(); var newIdentifier = '\0'; var rex = new Regex("_([a-z0-9])\\.mtrl"); if (!rex.IsMatch(_material.MTRLPath)) { return('a'); } for (var i = 1; i < alphabet.Length; i++) { var identifier = alphabet[i]; var newPath = Regex.Replace(_material.MTRLPath, "_([a-z0-9])\\.mtrl", "_" + identifier + ".mtrl"); var exists = await _index.FileExists(newPath); if (!exists) { return(identifier); } } // No empty material names left. // Note - This can be fixed. Materials don't need to be named a-z, but realisitcally is anyone going to have more than 26 materials? if (newIdentifier == '\0') { if (materialIdentifier == '\0') { newIdentifier = 'a'; } else { throw new NotSupportedException("Maximum Material Limit Reached."); } } return(newIdentifier); }
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); } }
private async Task LoadItems() { List <string> children = new List <string>(); var root = _item.GetRoot(); if (root != null) { if (_level == XivDependencyLevel.Model) { children = await root.GetModelFiles(); } else if (_level == XivDependencyLevel.Material) { var imc = new Imc(XivCache.GameInfo.GameDirectory); try { var entry = await imc.GetImcInfo((IItemModel)_item); children = await root.GetMaterialFiles(entry.MaterialSet); } catch { if (root.Info.SecondaryType == XivItemType.hair || root.Info.SecondaryType == XivItemType.tail || (root.Info.PrimaryType == XivItemType.human && root.Info.SecondaryType == XivItemType.body)) { // These types don't have IMC entries, but have a material variant number. // Kind of weird, but whatever. children = await root.GetMaterialFiles(1); } else { children = await root.GetMaterialFiles(0); } } } else if (_level == XivDependencyLevel.Texture) { try { var imc = new Imc(XivCache.GameInfo.GameDirectory); var entry = await imc.GetImcInfo((IItemModel)_item); children = await root.GetTextureFiles(entry.MaterialSet); } catch { if (root.Info.SecondaryType == XivItemType.hair || root.Info.SecondaryType == XivItemType.tail || (root.Info.PrimaryType == XivItemType.human && root.Info.SecondaryType == XivItemType.body)) { // These types don't have IMC entries, but have a material variant number. // Kind of weird, but whatever. children = await root.GetTextureFiles(1); } else { children = await root.GetTextureFiles(0); } } } else { // Invalid or root, nothing listed. } } var index = new Index(XivCache.GameInfo.GameDirectory); foreach (var file in children) { var exists = await index.FileExists(file); if (!exists) { continue; } Files.Add(new FileEntry(file)); } }
/// <summary> /// Saves a set of IMC entries to file. /// </summary> /// <param name="path"></param> /// <param name="entries"></param> /// <returns></returns> internal async Task SaveEntries(string path, string slot, List <XivImc> entries, IItem referenceItem = null, IndexFile cachedIndexFile = null, ModList cachedModList = null) { var dat = new Dat(_gameDirectory); var index = new Index(_gameDirectory); var exists = await index.FileExists(path); FullImcInfo info; if (exists) { info = await GetFullImcInfo(path, cachedIndexFile, cachedModList); } else { var ri = XivDependencyGraph.ExtractRootInfo(path); if (ri.SecondaryType == null) { info = new FullImcInfo() { DefaultSubset = new List <XivImc>() { new XivImc(), new XivImc(), new XivImc(), new XivImc(), new XivImc() }, SubsetList = new List <List <XivImc> >(), TypeIdentifier = ImcType.Set }; } else { info = new FullImcInfo() { DefaultSubset = new List <XivImc>() { new XivImc() }, SubsetList = new List <List <XivImc> >(), TypeIdentifier = ImcType.NonSet }; } } for (int i = 0; i < entries.Count; i++) { XivImc e; if (i >= info.SubsetCount + 1) { e = new XivImc(); } else { e = info.GetEntry(i, slot); } e.Mask = entries[i].Mask; e.Decal = entries[i].Decal; e.Vfx = entries[i].Vfx; e.Animation = entries[i].Animation; e.MaterialSet = entries[i].MaterialSet; if (i >= info.SubsetCount + 1) { info.SetEntry(e, i, slot, true); } } // Save the modified info. await SaveFullImcInfo(info, path, Constants.InternalModSourceName, referenceItem, cachedIndexFile, cachedModList); }
public async Task SaveMulti() { var _imc = new Imc(XivCache.GameInfo.GameDirectory); var _index = new Index(XivCache.GameInfo.GameDirectory); // Get tokenized map info structs. // This will let us set them in the new Materials and // Detokenize them using the new paths. var mapInfos = _material.GetAllMapInfos(true); // Shader info likewise will be pumped into each new material. var shaderInfo = _material.GetShaderInfo(); // Add new Materials for shared model items. var oldMaterialIdentifier = _material.GetMaterialIdentifier(); var oldMtrlName = Path.GetFileName(_material.MTRLPath); // Ordering these by name ensures that we create textures for the new variants in the first // item alphabetically, just for consistency's sake. var sameModelItems = (await _item.GetSharedModelItems()).OrderBy(x => x.Name, new ItemNameComparer()); var oldVariantString = "/v" + _material.GetVariant().ToString().PadLeft(4, '0') + '/'; var modifiedVariants = new List <int>(); var mtrlReplacementRegex = "_" + oldMaterialIdentifier + ".mtrl"; var mtrlReplacementRegexResult = "_" + _newMaterialIdentifier + ".mtrl"; if (_mode == MaterialEditorMode.NewRace) { mtrlReplacementRegexResult = mtrlReplacementRegex; } var newMtrlName = oldMtrlName.Replace(mtrlReplacementRegex, mtrlReplacementRegexResult); var root = _item.GetRootInfo(); var imcEntries = new List <XivImc>(); var materialSets = new HashSet <byte>(); try { var imcInfo = await _imc.GetFullImcInfo(_item); imcEntries = imcInfo.GetAllEntries(root.Slot, true); materialSets = imcEntries.Select(x => x.MaterialSet).ToHashSet(); } catch { // Item doesn't use IMC entries, and thus only has a single variant. materialSets.Clear(); materialSets.Add(0); } // We need to save our non-existent base material once before we can continue. if (_mode == MaterialEditorMode.NewRace) { await _mtrl.ImportMtrl(_material, _item, XivStrings.TexTools); } var count = 0; var allItems = (await root.ToFullRoot().GetAllItems()); var matNumToItems = new Dictionary <int, List <IItemModel> >(); foreach (var i in allItems) { if (imcEntries.Count <= i.ModelInfo.ImcSubsetID) { continue; } var matSet = imcEntries[i.ModelInfo.ImcSubsetID].MaterialSet; if (!matNumToItems.ContainsKey(matSet)) { matNumToItems.Add(matSet, new List <IItemModel>()); } var saveItem = i; if (typeof(XivCharacter) == i.GetType()) { var temp = (XivCharacter)((XivCharacter)_item).Clone(); temp.Name = saveItem.SecondaryCategory; saveItem = temp; } matNumToItems[matSet].Add(saveItem); } var keys = matNumToItems.Keys.ToList(); foreach (var key in keys) { var list = matNumToItems[key]; matNumToItems[key] = list.OrderBy(x => x.Name, new ItemNameComparer()).ToList(); } // Load and modify all the MTRLs. foreach (var materialSetId in materialSets) { var variantPath = _mtrl.GetMtrlFolder(root, materialSetId); var oldMaterialPath = variantPath + "/" + oldMtrlName; var newMaterialPath = variantPath + "/" + newMtrlName; // Don't create materials for set 0. (SE sets the material ID to 0 when that particular set-slot doesn't actually exist as an item) if (materialSetId == 0 && imcEntries.Count > 0) { continue; } var dxVersion = 11; XivMtrl itemXivMtrl; // Get mtrl path if (await _index.FileExists(oldMaterialPath)) { // Use the Material from this variant as a base? itemXivMtrl = await _mtrl.GetMtrlData(_item, oldMaterialPath, dxVersion); } else { itemXivMtrl = await _mtrl.GetMtrlData(_item, _material.MTRLPath, dxVersion); } // If we're an item that doesn't use IMC variants, make sure we don't accidentally move the material around. if (materialSetId != 0) { // Shift the MTRL to the new variant folder. itemXivMtrl.MTRLPath = Regex.Replace(itemXivMtrl.MTRLPath, oldVariantString, "/v" + materialSetId.ToString().PadLeft(4, '0') + "/"); } if (_mode == MaterialEditorMode.NewMulti) { // Change the MTRL part identifier. itemXivMtrl.MTRLPath = Regex.Replace(itemXivMtrl.MTRLPath, mtrlReplacementRegex, mtrlReplacementRegexResult); } // Load the Shader Settings itemXivMtrl.SetShaderInfo(shaderInfo, true); // Loop our tokenized map infos and pump them back in // using the new modified material to detokenize them. foreach (var info in mapInfos) { itemXivMtrl.SetMapInfo(info.Usage, (MapInfo)info.Clone()); } IItem item; try { item = matNumToItems[materialSetId].First(); } catch { item = (await XivCache.GetFirstRoot(itemXivMtrl.MTRLPath)).GetFirstItem(); } count++; // Write the new Material await _mtrl.ImportMtrl(itemXivMtrl, item, XivStrings.TexTools); _view.SaveStatusLabel.Content = "Updated " + count + "/" + materialSets.Count + " Material Sets..."; } }