static async Task BatchExportItem(string path, IItemModel item, XivModelInfo secondaryModelInfo, Func <Task <List <XivRace> > > getRaces) { if (File.Exists(path)) { return; } WriteLine($"Exporting {item.GetType().Name} {item.Name}: {Path.GetFileNameWithoutExtension(path)}"); var metadata = new ExportMetadata(); metadata.Name = item.Name; var mdl = new Mdl(_gameDir, item.DataFile); var races = await getRaces(); foreach (var race in races) { var mdlData = await mdl.GetMdlData(item, race, secondaryModelInfo); var textures = await TexTools.MaterialsHelper.GetMaterials(_gameDir, item, mdlData, race); var set = BatchExportSet(mdlData, textures); set.Name = TexTools.XivStringRaces.ToRaceGenderName(race); metadata.Sets.Add(set); } var metadataJson = JsonConvert.SerializeObject(metadata); File.WriteAllText(path, metadataJson); }
/// <summary> /// The event handler for the advanced options button clicked /// </summary> private async void AdvOptionsButton_Click(object sender, RoutedEventArgs e) { var selectedItem = ModelTypeComboBox.SelectedItem as ModComboBox; var mod = selectedItem.SelectedMod; var includedMod = new IncludedMods { Name = $"{Path.GetFileNameWithoutExtension(mod.fullPath)} ({((Category)ModListTreeView.SelectedItem).Name})", FullPath = mod.fullPath }; var itemModel = MakeItemModel(mod); var includedModsList = IncludedModsList.Items.Cast <IncludedMods>().ToList(); var mdl = new Mdl(_gameDirectory, XivDataFiles.GetXivDataFile(mod.datFile)); try { // TODO - Include Submesh ID ? // Do we even have any kind of UI To specify this in the wizard? // Submeshes are only used for Furniture anyways, so it might be a 'will not fix' bool success = await ImportModelView.ImportModel(itemModel, IOUtil.GetRaceFromPath(mod.fullPath), null, this, null, true); if (!success) { return; } } catch (Exception ex) { FlexibleMessageBox.Show(ex.Message, UIMessages.AdvancedImportErrorTitle, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } var mdlData = ImportModelView.GetData(); if (includedModsList.Any(item => item.Name.Equals(includedMod.Name))) { if (FlexibleMessageBox.Show( string.Format(UIMessages.ExistingOption, includedMod.Name), UIMessages.OverwriteTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes) { _selectedModOption.Mods[mod.fullPath].ModDataBytes = mdlData; } } else { IncludedModsList.Items.Add(includedMod); _selectedModOption.Mods.Add(mod.fullPath, new ModData { Name = mod.name, Category = mod.category, FullPath = mod.fullPath, ModDataBytes = mdlData, }); } }
/// <summary> /// The event handler for the advanced options button clicked /// </summary> private async void AdvOptionsButton_Click(object sender, RoutedEventArgs e) { var selectedFile = ModelTypeComboBox.SelectedItem as FileEntry; var itemModel = (IItemModel)SelectedItem; var mdl = new Mdl(_gameDirectory, IOUtil.GetDataFileFromPath(selectedFile.Path)); try { // TODO - Include Submesh ID ? // Do we even have any kind of UI To specify this in the wizard? // Submeshes are only used for Furniture anyways, so it might be a 'will not fix' bool success = await ImportModelView.ImportModel(itemModel, IOUtil.GetRaceFromPath(selectedFile.Path), null, this, null, true); if (!success) { return; } } catch (Exception ex) { FlexibleMessageBox.Show(ex.Message, UIMessages.AdvancedImportErrorTitle, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } var mdlData = ImportModelView.GetData(); AddFile(selectedFile, SelectedItem, mdlData); }
/// <summary> /// The event handler for the custom model button clicked /// </summary> private async void AddCustomModelButton_Click(object sender, RoutedEventArgs e) { var selectedItem = ModelTypeComboBox.SelectedItem as ModComboBox; var mod = selectedItem.SelectedMod; var includedMod = new IncludedMods { Name = $"{Path.GetFileNameWithoutExtension(mod.fullPath)} ({((Category)ModListTreeView.SelectedItem).Name})", FullPath = mod.fullPath }; var itemModel = MakeItemModel(mod); var includedModsList = IncludedModsList.Items.Cast <IncludedMods>().ToList(); var mdl = new Mdl(_gameDirectory, XivDataFiles.GetXivDataFile(mod.datFile)); var xivMdl = await mdl.GetMdlData(itemModel, GetRace(mod.fullPath), null, null, mod.data.originalOffset); var warnings = await mdl.ImportModel(itemModel, xivMdl, new DirectoryInfo(CustomModelTextBox.Text), null, XivStrings.TexTools, Settings.Default.DAE_Plugin_Target, true); if (warnings.Count > 0) { foreach (var warning in warnings) { FlexibleMessageBox.Show( $"{warning.Value}", $"{warning.Key}", MessageBoxButtons.OK, MessageBoxIcon.Warning); } } var mdlData = mdl.MDLRawData; if (includedModsList.Any(item => item.Name.Equals(includedMod.Name))) { if (FlexibleMessageBox.Show( string.Format(UIMessages.ExistingOption, includedMod.Name), UIMessages.OverwriteTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes) { _selectedModOption.Mods[mod.fullPath].ModDataBytes = mdlData; } } else { IncludedModsList.Items.Add(includedMod); _selectedModOption.Mods.Add(mod.fullPath, new ModData { Name = mod.name, Category = mod.category, FullPath = mod.fullPath, ModDataBytes = mdlData }); } }
public void MdlInitialize() { treeView1.Nodes.Clear(); TreeNode tn1 = new TreeNode("0"); Mdl mdl = Mdls.Single(m => m.parentcode == "0"); tn1.Tag = mdl; tn1.Text = mdl.form; treeView1.Nodes.Add(tn1); this.Bind(tn1); treeView1.Font = new Font("宋体", 15, FontStyle.Bold); treeView1.ExpandAll(); }
/// <summary> /// Método para editar um registro /// </summary> /// <param name="mdl"></param> public void Update(Mdl mdl) { try { AbrirConexão(); ExecuteNonQuery(GetSqlUpdate(mdl)); } catch (Exception ex) { MessageBox.Show("Houve um erro: \n" + ex); } finally { FecharConexao(); } }
/// <summary> /// The event handler for the advanced options button clicked /// </summary> private void AdvOptionsButton_Click(object sender, RoutedEventArgs e) { var selectedItem = ModelTypeComboBox.SelectedItem as ModComboBox; var mod = selectedItem.SelectedMod; var includedMod = new IncludedMods { Name = $"{Path.GetFileNameWithoutExtension(mod.fullPath)} ({((Category)ModListTreeView.SelectedItem).Name})", FullPath = mod.fullPath }; var itemModel = MakeItemModel(mod); var includedModsList = IncludedModsList.Items.Cast <IncludedMods>().ToList(); var mdl = new Mdl(_gameDirectory, XivDataFiles.GetXivDataFile(mod.datFile)); var xivMdl = mdl.GetMdlData(itemModel, GetRace(mod.fullPath), null, null, mod.data.originalOffset); var advancedImportView = new AdvancedModelImportView(xivMdl, itemModel, GetRace(mod.fullPath), true); var result = advancedImportView.ShowDialog(); if (result == true) { if (includedModsList.Any(item => item.Name.Equals(includedMod.Name))) { if (FlexibleMessageBox.Show( $"This Option already includes {includedMod.Name} \n\n Would you like to overwrite the existing mod for this option?", "Overwrite?", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes) { _selectedModOption.Mods[mod.fullPath].ModDataBytes = advancedImportView.RawModelData; } } else { IncludedModsList.Items.Add(includedMod); _selectedModOption.Mods.Add(mod.fullPath, new ModData { Name = mod.name, Category = mod.category, FullPath = mod.fullPath, ModDataBytes = advancedImportView.RawModelData }); } } }
/// <summary> /// The event handler for the custom model button clicked /// </summary> private void AddCustomModelButton_Click(object sender, RoutedEventArgs e) { var selectedItem = ModelTypeComboBox.SelectedItem as ModComboBox; var mod = selectedItem.SelectedMod; var includedMod = new IncludedMods { Name = $"{Path.GetFileNameWithoutExtension(mod.fullPath)} ({((Category)ModListTreeView.SelectedItem).Name})", FullPath = mod.fullPath }; var itemModel = MakeItemModel(mod); var includedModsList = IncludedModsList.Items.Cast <IncludedMods>().ToList(); var mdl = new Mdl(_gameDirectory, XivDataFiles.GetXivDataFile(mod.datFile)); var xivMdl = mdl.GetMdlData(itemModel, GetRace(mod.fullPath)); var importResults = mdl.ImportModel(itemModel, xivMdl, new DirectoryInfo(CustomModelTextBox.Text), null, XivStrings.TexTools, true); //TODO: Add dialogs for import results (warning messages) var mdlData = mdl.MDLRawData; if (includedModsList.Any(item => item.Name.Equals(includedMod.Name))) { if (FlexibleMessageBox.Show( $"This Option already includes {includedMod.Name} \n\n Would you like to overwrite the existing mod for this option?", "Overwrite?", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes) { _selectedModOption.Mods[mod.fullPath].ModDataBytes = mdlData; } } else { IncludedModsList.Items.Add(includedMod); _selectedModOption.Mods.Add(mod.fullPath, new ModData { Name = mod.name, Category = mod.category, FullPath = mod.fullPath, ModDataBytes = mdlData }); } }
/// <summary> /// Monta o sql de insert /// </summary> /// <param name="mdl">Model</param> /// <returns>Retorna sql para adicionar no banco</returns> private string GetSqlInsert(Mdl mdl) { string sql = $@"INSERT INTO {mdl.GetType().Name} ("; #region CAMPOS bool first = true; foreach (var campo in mdl.GetType().GetProperties()) { //Verifica se o campo não é do Mdl (o id fica guardado lá) if (campo.DeclaringType.Name != "Mdl") { sql += first ? "" : ", "; first = false; sql += campo.Name; } } #endregion sql += $@") VALUES("; #region VALUES first = true; foreach (var campo in mdl.GetType().GetProperties()) { //Verifica se o campo não é do Mdl (o id fica guardado lá) if (campo.DeclaringType.Name != "Mdl") { sql += first ? "" : ", "; first = false; sql += "'" + campo.GetValue(mdl, null) + "'"; } } #endregion sql += ");"; return(sql); }
/// <summary> /// Método para excluir um registro /// </summary> /// <param name="mdl"></param> public void Delete(Mdl mdl) { try { AbrirConexão(); string sql = $@"DELETE FROM {mdl.GetType().Name} WHERE id = {mdl.Id};"; ExecuteNonQuery(sql); } catch (Exception ex) { MessageBox.Show("Houve um erro: \n" + ex); } finally { FecharConexao(); } }
private async Task <string> GetInternalSkelName(string fullMdlPath) { if (IsFurnishing(fullMdlPath)) { return(null); } var mdlPath = fullMdlPath; var mdlName = Path.GetFileName(fullMdlPath); var skelName = mdlName.Substring(0, 5); if (IsHat(fullMdlPath) || IsFace(fullMdlPath)) { skelName = mdlName.Substring(5, 5); } else if (IsHair(mdlPath)) { // This part sucks, gotta load the MDL and scrape the bone list // to look for hair EX bones. // No real getting around it until we find out how skeletons are set in game. var _mdl = new Mdl(_gameDirectory, IOUtil.GetDataFileFromPath(fullMdlPath)); var model = await _mdl.GetModel(fullMdlPath, true); // Get the OG skel for the hair, don't trick users into thinking they can add EX bones. // This process technically should also be done for other gear slots that might have EX Bones. // But that's both rare, and this process is expensive, so we don't, and instead just package EX bone sets // in with the TexTools distributable. if (model.Bones.Any(x => x.Contains("x_h"))) { var bone = model.Bones.First(x => x.Contains("x_h")); skelName = bone.Substring(bone.IndexOf("x_h") + 2, 5); } else { skelName = mdlName.Substring(5, 5); } } return(skelName); }
/// <summary> /// Monta o sql de update /// </summary> /// <param name="mdl">Model</param> /// <returns>Retorna sql para editar no banco</returns> private string GetSqlUpdate(Mdl mdl) { string sql = $"UPDATE {mdl.GetType().Name} SET "; bool first = true; foreach (var campo in mdl.GetType().GetProperties()) { //Verifica se o campo não é do Mdl (o id fica guardado lá) if (campo.DeclaringType.Name != "Mdl") { sql += first ? "" : ", "; first = false; sql += campo.Name; sql += " = '" + campo.GetValue(mdl, null) + "'"; } } sql += $" WHERE id = {mdl.Id};"; return(sql); }
/// <summary> /// Retorna DataTable com todas informações do banco /// </summary> /// <param name="mdl"></param> /// <returns>DataTable com todas informações do banco</returns> protected DataTable GetDataTable(Mdl mdl) { DataTable dt = new DataTable(); try { AbrirConexão(); string sql = $"SELECT * FROM {mdl.GetType().Name};"; dt = ExecuteDataTable(sql); } catch (Exception ex) { MessageBox.Show("Houve um erro: \n" + ex); } finally { FecharConexao(); } return(dt); }
private async void CopyButton_Click(object sender, RoutedEventArgs e) { var to = ToBox.Text; var from = FromBox.Text; try { if (string.IsNullOrWhiteSpace(to) || string.IsNullOrWhiteSpace(from)) { return; } to = to.Trim().ToLower(); from = from.Trim().ToLower(); if (!to.EndsWith(".mdl") || !from.EndsWith(".mdl")) { return; } var toRoot = await XivCache.GetFirstRoot(to); var fromRoot = await XivCache.GetFirstRoot(from); var df = IOUtil.GetDataFileFromPath(to); var _mdl = new Mdl(XivCache.GameInfo.GameDirectory, df); await _mdl.CopyModel(from, to, XivStrings.TexTools, true); FlexibleMessageBox.Show("Model Copied Successfully.", "Model Copy Confirmation", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Information); Close(); } catch (Exception ex) { FlexibleMessageBox.Show("Model Copied Failed.\n\nError: " + ex.Message, "Model Copy Error", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error); } }
private void treeView1_AfterSelect(object sender, TreeViewEventArgs e) { if (e.Node.Tag is Mdl) { Mdl mdl = (Mdl)e.Node.Tag; this.panel4.Controls.Clear(); switch (mdl.form) { case "FormLogin": FrmLogin formLogin = Program.programContainer.GetExportedValue <FrmLogin>(); formLogin.TopLevel = false; formLogin.Dock = DockStyle.Fill; formLogin.Show(); this.panel4.Controls.Add(formLogin); ApplyResource(typeof(FrmLogin)); break; case "FrmGoodNG": FrmGoodNg frmGoodNG = Program.programContainer.GetExportedValue <FrmGoodNg>(); frmGoodNG.TopLevel = false; frmGoodNG.Dock = DockStyle.Fill; frmGoodNG.Show(); this.panel4.Controls.Add(frmGoodNG); ApplyResource(typeof(FrmGoodNg)); break; case "FrmTsInputEdit": FrmTsInputEdit frmTsInputEdit = Program.programContainer.GetExportedValue <FrmTsInputEdit>(); frmTsInputEdit.TopLevel = false; frmTsInputEdit.Dock = DockStyle.Fill; frmTsInputEdit.Show(); this.panel4.Controls.Add(frmTsInputEdit); ApplyResource(typeof(FrmTsInputEdit)); break; } } }
private bool Import(string path) { _mdls.Clear(); using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { IWorkbook workbook; var extension = Path.GetExtension(path); if (".xlsx".Equals(extension, StringComparison.CurrentCultureIgnoreCase)) { workbook = new XSSFWorkbook(fs); } else { workbook = new HSSFWorkbook(fs); } if (workbook.NumberOfSheets > 0) { var sheetAt0 = workbook.GetSheetAt(0); var cou = sheetAt0.LastRowNum; for (var i = 1; i < cou + 1; i++) { var mdl = new Mdl(); var rowHeader = sheetAt0.GetRow(i); mdl.X = rowHeader.GetCell(0).NumericCellValue; mdl.Y = rowHeader.GetCell(1).NumericCellValue; mdl.Z = rowHeader.GetCell(2).NumericCellValue; mdl.Value = rowHeader.GetCell(3).NumericCellValue; _mdls.Add(mdl); } } } return(true); }
public virtual OperationResult AddEntity(Mdl mdl, bool isSave = true) { return(mdlRepository.Insert(mdl, isSave)); }
private static async Task Export(string part, IItemModel item, XivRace desiredRace) { if (item == null) { return; } MainWin.LockProgress.Report($"Exporting {part}: {item.Name}"); Mdl _mdl = new Mdl(GameDirectory, item.DataFile); TTModel model = await _mdl.GetModel(item, desiredRace); XivRace modelRace = desiredRace; if (model == null) { List <XivRace> priority = desiredRace.GetModelPriorityList(); foreach (XivRace newRace in priority) { model = await _mdl.GetModel(item, newRace); modelRace = newRace; if (model != null) { break; } } } if (model == null) { throw new Exception($"Failed to get model for item: {item}"); } if (!Directory.Exists($"/{name}/{part}/")) { Directory.CreateDirectory($"/{name}/{part}/"); } string path = $"/{name}/{part}/{item.Name}.fbx"; if (desiredRace != modelRace) { ApplyDeformers(model, modelRace, desiredRace); } await _mdl.ExportModel(model, path); MainWin.LockProgress.Report($"Converting Normals {part}: {item.Name}"); string[] normalMaps = Directory.GetFiles(Path.GetDirectoryName(path), "*_n.png"); foreach (string normalMap in normalMaps) { string disMap = normalMap.Replace("_n.png", "_dis.png"); ProcessStartInfo processStartInfo = new ProcessStartInfo(); processStartInfo.FileName = "NormalToHeight.exe"; processStartInfo.Arguments = $"{normalMap} {disMap} -normalise"; processStartInfo.CreateNoWindow = true; processStartInfo.WindowStyle = ProcessWindowStyle.Hidden; Process proc = Process.Start(processStartInfo); while (!proc.HasExited) { await Task.Delay(100); } } }
public async Task <bool> Save() { if (_metadata == null) { return(false); } var success = false; try { await MainWindow.GetMainWindow().LockUi("Updating Metadata"); await ItemMetadata.SaveMetadata(_metadata, XivStrings.TexTools); var _mdl = new Mdl(XivCache.GameInfo.GameDirectory, IOUtil.GetDataFileFromPath(_metadata.Root.Info.GetRootFile())); foreach (var kv in _metadata.EqdpEntries) { if (kv.Value.bit1 == false) { continue; } if (_original.EqdpEntries[kv.Key].bit1 == true) { continue; } // Here we have a new race, we need to create a model for it. await _mdl.AddRacialModel(_metadata.Root.Info.PrimaryId, _metadata.Root.Info.Slot, kv.Key, XivStrings.TexTools); } if (_metadata.ImcEntries.Count > 0) { var _dat = new Dat(XivCache.GameInfo.GameDirectory); var originalMaterialSetMax = _original.ImcEntries.Select(x => x.MaterialSet).Max(); var newMaterialSetMax = _metadata.ImcEntries.Select(x => x.MaterialSet).Max(); if (newMaterialSetMax > originalMaterialSetMax) { // We have new materials to add. // First find the base files to copy. (Just always copy from set 1 for simplicity) var copySource = await _metadata.Root.GetMaterialFiles(1); var item = _metadata.Root.GetFirstItem(); for (int i = originalMaterialSetMax + 1; i <= newMaterialSetMax; i++) { foreach (var material in copySource) { var dest = material.Replace("v0001", "v" + i.ToString().PadLeft(4, '0')); await _dat.CopyFile(material, dest, XivStrings.TexTools, false, item); } } } } success = true; } catch (Exception Ex) { Helpers.FlexibleMessageBox.Show("An Error occured while saving the Metadata: \n" + Ex.Message, "Metadata Error", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error, System.Windows.Forms.MessageBoxDefaultButton.Button1); } finally { await MainWindow.GetMainWindow().UnlockUi(); } if (success) { var mw = MainWindow.GetMainWindow(); mw.ReloadItem(); } return(success); }
public ImportModelViewModel(ImportModelView view, IItemModel item, XivRace race, string submeshId, bool dataOnly, Action onComplete = null, string lastImportFilePath = null) { _view = view; _item = item; _race = race; _submeshId = submeshId; _dataOnly = dataOnly; _onComplete = onComplete; _lastImportFilePath = lastImportFilePath; if (typeof(XivCharacter) == _item.GetType()) { // Fix up naming scheme for character items to match user expectation. var clone = (XivCharacter)((XivCharacter)_item).Clone(); clone.Name = clone.SecondaryCategory; _item = clone; } var gameDirectory = new DirectoryInfo(Settings.Default.FFXIV_Directory); var saveDirectory = new DirectoryInfo(Settings.Default.Save_Directory); var dataFile = IOUtil.GetDataFileFromPath(_item.GetItemRootFolder()); _mdl = new Mdl(gameDirectory, dataFile); _importers = _mdl.GetAvailableImporters(); SetupRaces(); // We need to explicitly fork this onto a new thread to avoid deadlock. Task.Run(AssignPath).Wait(); var defaultPath = $"{IOUtil.MakeItemSavePath(_item, saveDirectory, _race)}\\3D".Replace("/", "\\"); var modelName = Path.GetFileNameWithoutExtension(_internalPath); // Scan to see which file type(s) actually exist. bool foundValidFile = false; // FBX is default, so check that first. var startingPath = Path.Combine(defaultPath, modelName) + ".fbx"; if (File.Exists(startingPath)) { foundValidFile = true; } if (!foundValidFile) { foreach (var suffix in _importers) { startingPath = Path.Combine(defaultPath, modelName) + "." + suffix; if (File.Exists(startingPath)) { foundValidFile = true; break; } } } if (!foundValidFile) { // Auto-fill the last import file path if the file still exists, otherwise just default to reusing the existing model startingPath = File.Exists(_lastImportFilePath) ? _lastImportFilePath : ""; } _view.FileNameTextBox.Text = startingPath; // Event Handlers _view.SelectFileButton.Click += SelectFileButton_Click; _view.ImportButton.Click += ImportButton_Click; _view.EditButton.Click += EditButton_Click; _view.Closing += _view_Closing; _view.OverrideRaceButton.Checked += OverrideRaceButton_Checked; _view.OverrideRaceButton.Unchecked += OverrideRaceButton_Unchecked; // Default Settings for specific categories, event handlers are added to allow users to opt out of these defaults if (item.SecondaryCategory == XivStrings.Face) { _view.UseOriginalShapeDataButton.IsChecked = Settings.Default.UseOriginalShapeDataForFace; _view.UseOriginalShapeDataButton.Click += UseOriginalShapeDataButton_Clicked; } if (item.SecondaryCategory == XivStrings.Hair) { _view.CloneUV1Button.IsChecked = Settings.Default.CloneUV1toUV2ForHair; _view.CloneUV1Button.Click += CloneUV1Button_Clicked; } var iType = item.GetPrimaryItemType(); if (iType == xivModdingFramework.Items.Enums.XivItemType.equipment || iType == xivModdingFramework.Items.Enums.XivItemType.accessory || iType == xivModdingFramework.Items.Enums.XivItemType.weapon) { _view.ForceUVsButton.IsChecked = Settings.Default.ForceUV1QuadrantForGear; _view.ForceUVsButton.Click += ForceUVsButton_Clicked; } }
/// <summary> /// Exports the model /// </summary> /// <param name="fullModelName">The name chosen by the user for the full model export</param> private async Task Export(string fullModelName) { var pc = await this.ShowProgressAsync(UIMessages.ExportingFullModelTitle, UIMessages.PleaseStandByMessage); var fileFormat = "fbx"; var savePath = new DirectoryInfo(Settings.Default.Save_Directory); var outputFilePath = $"{savePath}\\FullModel\\{fullModelName}\\{fullModelName}.{fileFormat}"; // Create output directory Directory.CreateDirectory($"{savePath}\\FullModel\\{fullModelName}"); var fmViewPortVM = viewport3DX.DataContext as FullModelViewport3DViewModel; var converterFolder = Directory.GetCurrentDirectory() + "\\converters\\" + fileFormat; Directory.CreateDirectory(converterFolder); var dbPath = converterFolder + "\\input.db"; File.Delete(dbPath); // Create the DB where all models will be added and fill the metadata fmViewPortVM.shownModels.FirstOrDefault().Value.TtModel.SetFullModelDBMetaData(dbPath, fullModelName); // Export the materials for each model and save model to DB foreach (var model in fmViewPortVM.shownModels) { var mtrlVariant = 1; try { var imc = new Imc(_gameDirectory); mtrlVariant = (await imc.GetImcInfo(model.Value.ItemModel)).MaterialSet; } catch (Exception ex) { // No-op, defaulted to 1. } await Mdl.ExportMaterialsForModel(model.Value.TtModel, outputFilePath, _gameDirectory, mtrlVariant, _fmvm.SelectedSkeleton.XivRace); // Save model to DB } TTModel.SaveFullToFile(dbPath, _fmvm.SelectedSkeleton.XivRace, fmViewPortVM.shownModels.Select(x => x.Value.TtModel).ToList()); var proc = new Process { StartInfo = new ProcessStartInfo { FileName = converterFolder + "\\converter.exe", Arguments = "\"" + dbPath + "\"", RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, WorkingDirectory = "" + converterFolder + "", CreateNoWindow = true } }; proc.Start(); proc.WaitForExit(); var code = proc.ExitCode; if (code != 0) { throw new Exception("Exporter threw error code: " + proc.ExitCode); } var outputFile = converterFolder + "\\result." + fileFormat; // Just move the result file if we need to. if (!Path.Equals(outputFilePath, outputFile)) { File.Delete(outputFilePath); File.Move(outputFile, outputFilePath); } await pc.CloseAsync(); await this.ShowMessageAsync(UIMessages.FullModelExportSuccessTitle, string.Format(UIMessages.FullModelExportSuccessMessage, outputFilePath)); }
/// <summary> /// Copies the entirety of a given root to a new root. /// </summary> /// <param name="Source">Original Root to copy from.</param> /// <param name="Destination">Destination root to copy to.</param> /// <param name="ApplicationSource">Application to list as the source for the resulting mod entries.</param> /// <returns>Returns a Dictionary of all the file conversion</returns> public static async Task <Dictionary <string, string> > CloneRoot(XivDependencyRoot Source, XivDependencyRoot Destination, string ApplicationSource, int singleVariant = -1, string saveDirectory = null, IProgress <string> ProgressReporter = null, IndexFile index = null, ModList modlist = null, ModPack modPack = null) { if (!IsSupported(Source) || !IsSupported(Destination)) { throw new InvalidDataException("Cannot clone unsupported root."); } if (ProgressReporter != null) { ProgressReporter.Report("Stopping Cache Worker..."); } var workerStatus = XivCache.CacheWorkerEnabled; XivCache.CacheWorkerEnabled = false; try { var df = IOUtil.GetDataFileFromPath(Source.ToString()); var _imc = new Imc(XivCache.GameInfo.GameDirectory); var _mdl = new Mdl(XivCache.GameInfo.GameDirectory, df); var _dat = new Dat(XivCache.GameInfo.GameDirectory); var _index = new Index(XivCache.GameInfo.GameDirectory); var _mtrl = new Mtrl(XivCache.GameInfo.GameDirectory); var _modding = new Modding(XivCache.GameInfo.GameDirectory); var doSave = false; if (index == null) { doSave = true; index = await _index.GetIndexFile(df); modlist = await _modding.GetModListAsync(); } bool locked = _index.IsIndexLocked(df); if (locked) { throw new Exception("Game files currently in use."); } if (ProgressReporter != null) { ProgressReporter.Report("Analyzing items and variants..."); } // First, try to get everything, to ensure it's all valid. ItemMetadata originalMetadata = await GetCachedMetadata(index, modlist, Source, df, _dat); var originalModelPaths = await Source.GetModelFiles(index, modlist); var originalMaterialPaths = await Source.GetMaterialFiles(-1, index, modlist); var originalTexturePaths = await Source.GetTextureFiles(-1, index, modlist); var originalVfxPaths = new HashSet <string>(); if (Imc.UsesImc(Source)) { var avfxSets = originalMetadata.ImcEntries.Select(x => x.Vfx).Distinct(); foreach (var avfx in avfxSets) { var avfxStuff = await ATex.GetVfxPath(Source.Info, avfx); if (String.IsNullOrEmpty(avfxStuff.Folder) || String.IsNullOrEmpty(avfxStuff.File)) { continue; } var path = avfxStuff.Folder + "/" + avfxStuff.File; if (index.FileExists(path)) { originalVfxPaths.Add(path); } } } // Time to start editing things. // First, get a new, clean copy of the metadata, pointed at the new root. var newMetadata = await GetCachedMetadata(index, modlist, Source, df, _dat); newMetadata.Root = Destination.Info.ToFullRoot(); ItemMetadata originalDestinationMetadata = null; try { originalDestinationMetadata = await GetCachedMetadata(index, modlist, Destination, df, _dat); } catch { originalDestinationMetadata = new ItemMetadata(Destination); } // Set 0 needs special handling. if (Source.Info.PrimaryType == XivItemType.equipment && Source.Info.PrimaryId == 0) { var set1Root = new XivDependencyRoot(Source.Info.PrimaryType, 1, null, null, Source.Info.Slot); var set1Metadata = await GetCachedMetadata(index, modlist, set1Root, df, _dat); newMetadata.EqpEntry = set1Metadata.EqpEntry; if (Source.Info.Slot == "met") { newMetadata.GmpEntry = set1Metadata.GmpEntry; } } else if (Destination.Info.PrimaryType == XivItemType.equipment && Destination.Info.PrimaryId == 0) { newMetadata.EqpEntry = null; newMetadata.GmpEntry = null; } // Now figure out the path names for all of our new paths. // These dictionarys map Old Path => New Path Dictionary <string, string> newModelPaths = new Dictionary <string, string>(); Dictionary <string, string> newMaterialPaths = new Dictionary <string, string>(); Dictionary <string, string> newMaterialFileNames = new Dictionary <string, string>(); Dictionary <string, string> newTexturePaths = new Dictionary <string, string>(); Dictionary <string, string> newAvfxPaths = new Dictionary <string, string>(); if (ProgressReporter != null) { ProgressReporter.Report("Calculating files to copy..."); } // For each path, replace any instances of our primary and secondary types. foreach (var path in originalModelPaths) { newModelPaths.Add(path, UpdatePath(Source, Destination, path)); } foreach (var path in originalMaterialPaths) { var nPath = UpdatePath(Source, Destination, path); newMaterialPaths.Add(path, nPath); var fName = Path.GetFileName(path); if (!newMaterialFileNames.ContainsKey(fName)) { newMaterialFileNames.Add(fName, Path.GetFileName(nPath)); } } foreach (var path in originalTexturePaths) { newTexturePaths.Add(path, UpdatePath(Source, Destination, path)); } foreach (var path in originalVfxPaths) { newAvfxPaths.Add(path, UpdatePath(Source, Destination, path)); } var destItem = Destination.GetFirstItem(); var srcItem = (await Source.GetAllItems(singleVariant))[0]; var iCat = destItem.SecondaryCategory; var iName = destItem.Name; var files = newModelPaths.Select(x => x.Value).Union( newMaterialPaths.Select(x => x.Value)).Union( newAvfxPaths.Select(x => x.Value)).Union( newTexturePaths.Select(x => x.Value)); var allFiles = new HashSet <string>(); foreach (var f in files) { allFiles.Add(f); } allFiles.Add(Destination.Info.GetRootFile()); if (ProgressReporter != null) { ProgressReporter.Report("Getting modlist..."); } if (ProgressReporter != null) { ProgressReporter.Report("Removing existing modifications to destination root..."); } if (Destination != Source) { var dPath = Destination.Info.GetRootFolder(); var allMods = modlist.Mods.ToList(); foreach (var mod in allMods) { if (mod.fullPath.StartsWith(dPath) && !mod.IsInternal()) { if (Destination.Info.SecondaryType != null || Destination.Info.Slot == null) { // If this is a slotless root, purge everything. await _modding.DeleteMod(mod.fullPath, false, index, modlist); } else if (allFiles.Contains(mod.fullPath) || mod.fullPath.Contains(Destination.Info.GetBaseFileName(true))) { // Otherwise, only purge the files we're replacing, and anything else that // contains our slot name. await _modding.DeleteMod(mod.fullPath, false, index, modlist); } } } } if (ProgressReporter != null) { ProgressReporter.Report("Copying models..."); } // Load, Edit, and resave the model files. foreach (var kv in newModelPaths) { var src = kv.Key; var dst = kv.Value; var offset = index.Get8xDataOffset(src); var xmdl = await _mdl.GetRawMdlData(src, false, offset); var tmdl = TTModel.FromRaw(xmdl); if (xmdl == null || tmdl == null) { continue; } tmdl.Source = dst; xmdl.MdlPath = dst; // Replace any material references as needed. foreach (var m in tmdl.MeshGroups) { foreach (var matKv in newMaterialFileNames) { m.Material = m.Material.Replace(matKv.Key, matKv.Value); } } // Save new Model. var bytes = await _mdl.MakeNewMdlFile(tmdl, xmdl, null); await _dat.WriteModFile(bytes, dst, ApplicationSource, destItem, index, modlist); } if (ProgressReporter != null) { ProgressReporter.Report("Copying textures..."); } // Raw Copy all Texture files to the new destinations to avoid having the MTRL save functions auto-generate blank textures. foreach (var kv in newTexturePaths) { var src = kv.Key; var dst = kv.Value; await _dat.CopyFile(src, dst, ApplicationSource, true, destItem, index, modlist); } if (ProgressReporter != null) { ProgressReporter.Report("Copying materials..."); } HashSet <string> CopiedMaterials = new HashSet <string>(); // Load every Material file and edit the texture references to the new texture paths. foreach (var kv in newMaterialPaths) { var src = kv.Key; var dst = kv.Value; try { var offset = index.Get8xDataOffset(src); if (offset == 0) { continue; } var xivMtrl = await _mtrl.GetMtrlData(offset, src, 11); xivMtrl.MTRLPath = dst; for (int i = 0; i < xivMtrl.TexturePathList.Count; i++) { foreach (var tkv in newTexturePaths) { xivMtrl.TexturePathList[i] = xivMtrl.TexturePathList[i].Replace(tkv.Key, tkv.Value); } } await _mtrl.ImportMtrl(xivMtrl, destItem, ApplicationSource, index, modlist); CopiedMaterials.Add(dst); } catch (Exception ex) { // Let functions later handle this mtrl then. } } if (ProgressReporter != null) { ProgressReporter.Report("Copying VFX..."); } // Copy VFX files. foreach (var kv in newAvfxPaths) { var src = kv.Key; var dst = kv.Value; await _dat.CopyFile(src, dst, ApplicationSource, true, destItem, index, modlist); } if (ProgressReporter != null) { ProgressReporter.Report("Creating missing variants..."); } // Check to see if we need to add any variants var cloneNum = newMetadata.ImcEntries.Count >= 2 ? 1 : 0; while (originalDestinationMetadata.ImcEntries.Count > newMetadata.ImcEntries.Count) { // Clone Variant 1 into the variants we are missing. newMetadata.ImcEntries.Add((XivImc)newMetadata.ImcEntries[cloneNum].Clone()); } if (singleVariant >= 0) { if (ProgressReporter != null) { ProgressReporter.Report("Setting single-variant data..."); } if (singleVariant < newMetadata.ImcEntries.Count) { var v = newMetadata.ImcEntries[singleVariant]; for (int i = 0; i < newMetadata.ImcEntries.Count; i++) { newMetadata.ImcEntries[i] = (XivImc)v.Clone(); } } } // Update Skeleton references to be for the correct set Id. var setId = Destination.Info.SecondaryId == null ? (ushort)Destination.Info.PrimaryId : (ushort)Destination.Info.SecondaryId; foreach (var entry in newMetadata.EstEntries) { entry.Value.SetId = setId; } if (ProgressReporter != null) { ProgressReporter.Report("Copying metdata..."); } // Poke through the variants and adjust any that point to null Material Sets to instead use a valid one. if (newMetadata.ImcEntries.Count > 0 && originalMetadata.ImcEntries.Count > 0) { var valid = newMetadata.ImcEntries.FirstOrDefault(x => x.MaterialSet != 0).MaterialSet; if (valid <= 0) { valid = originalMetadata.ImcEntries.FirstOrDefault(x => x.MaterialSet != 0).MaterialSet; } for (int i = 0; i < newMetadata.ImcEntries.Count; i++) { var entry = newMetadata.ImcEntries[i]; if (entry.MaterialSet == 0) { entry.MaterialSet = valid; } } } await ItemMetadata.SaveMetadata(newMetadata, ApplicationSource, index, modlist); // Save the new Metadata file via the batch function so that it's only written to the memory cache for now. await ItemMetadata.ApplyMetadataBatched(new List <ItemMetadata>() { newMetadata }, index, modlist, false); if (ProgressReporter != null) { ProgressReporter.Report("Filling in missing material sets..."); } // Validate all variants/material sets for valid materials, and copy materials as needed to fix. if (Imc.UsesImc(Destination)) { var mSets = newMetadata.ImcEntries.Select(x => x.MaterialSet).Distinct(); foreach (var mSetId in mSets) { var path = Destination.Info.GetRootFolder() + "material/v" + mSetId.ToString().PadLeft(4, '0') + "/"; foreach (var mkv in newMaterialFileNames) { // See if the material was copied over. var destPath = path + mkv.Value; if (CopiedMaterials.Contains(destPath)) { continue; } string existentCopy = null; // If not, find a material where one *was* copied over. foreach (var mSetId2 in mSets) { var p2 = Destination.Info.GetRootFolder() + "material/v" + mSetId2.ToString().PadLeft(4, '0') + "/"; foreach (var cmat2 in CopiedMaterials) { if (cmat2 == p2 + mkv.Value) { existentCopy = cmat2; break; } } } // Shouldn't ever actually hit this, but if we do, nothing to be done about it. if (existentCopy == null) { continue; } // Copy the material over. await _dat.CopyFile(existentCopy, destPath, ApplicationSource, true, destItem, index, modlist); } } } if (ProgressReporter != null) { ProgressReporter.Report("Updating modlist..."); } if (modPack == null) { modPack = new ModPack() { author = "System", name = "Item Copy - " + srcItem.Name + " to " + iName, url = "", version = "1.0" }; } List <Mod> mods = new List <Mod>(); foreach (var mod in modlist.Mods) { if (allFiles.Contains(mod.fullPath)) { // Ensure all of our modified files are attributed correctly. mod.name = iName; mod.category = iCat; mod.source = ApplicationSource; mod.modPack = modPack; mods.Add(mod); } } if (!modlist.ModPacks.Any(x => x.name == modPack.name)) { modlist.ModPacks.Add(modPack); } if (doSave) { // Save everything. await _index.SaveIndexFile(index); await _modding.SaveModListAsync(modlist); } XivCache.QueueDependencyUpdate(allFiles.ToList()); if (saveDirectory != null) { ProgressReporter.Report("Creating TTMP File..."); var desc = "Item Converter Modpack - " + srcItem.Name + " -> " + iName + "\nCreated at: " + DateTime.Now.ToString(); // Time to save the modlist to file. var dir = new DirectoryInfo(saveDirectory); var _ttmp = new TTMP(dir, ApplicationSource); var smpd = new SimpleModPackData() { Author = modPack.author, Description = desc, Url = modPack.url, Version = new Version(1, 0, 0), Name = modPack.name, SimpleModDataList = new List <SimpleModData>() }; foreach (var mod in mods) { var size = await _dat.GetCompressedFileSize(mod.data.modOffset, df); var smd = new SimpleModData() { Name = iName, FullPath = mod.fullPath, DatFile = df.GetDataFileName(), Category = iCat, IsDefault = false, ModSize = size, ModOffset = mod.data.modOffset }; smpd.SimpleModDataList.Add(smd); } await _ttmp.CreateSimpleModPack(smpd, XivCache.GameInfo.GameDirectory, null, true); } if (ProgressReporter != null) { ProgressReporter.Report("Root copy complete."); } // Return the final file conversion listing. var ret = newModelPaths.Union(newMaterialPaths).Union(newAvfxPaths).Union(newTexturePaths); var dict = ret.ToDictionary(x => x.Key, x => x.Value); dict.Add(Source.Info.GetRootFile(), Destination.Info.GetRootFile()); return(dict); } finally { XivCache.CacheWorkerEnabled = workerStatus; } }
public virtual OperationResult UpdateEntity(Mdl mdl, bool isSave = true) { return(mdlRepository.Update(mdl, isSave)); }
static void BatchExportItem(string path, IItemModel item, XivModelInfo secondaryModelInfo, Func <IEnumerable <XivRace> > getRaces) { if (File.Exists(path)) { return; } WriteLine($"Exporting {item.GetType().Name} {item.Name}: {Path.GetFileNameWithoutExtension(path)}"); var items = new List <IItemModel>(); var metadata = new ExportMetadata(); metadata.Name = item.Name; var mdl = new Mdl(_gameDir, item.DataFile); var races = getRaces(); items.Add(item); if (item.ModelInfo is XivMonsterModelInfo) { var info = item.ModelInfo as XivMonsterModelInfo; if (info.ModelType.Equals(XivItemType.demihuman) && item is XivMount) { items.Clear(); var met = item.Clone() as XivMount; met.TertiaryCategory = "Head"; var top = item.Clone() as XivMount; top.TertiaryCategory = "Body"; var glv = item.Clone() as XivMount; glv.TertiaryCategory = "Hand"; var dwn = item.Clone() as XivMount; dwn.TertiaryCategory = "Leg"; var sho = item.Clone() as XivMount; sho.TertiaryCategory = "Feet"; items.Add(met); items.Add(top); items.Add(glv); items.Add(dwn); items.Add(sho); } } foreach (var race in races) { var mdlDatas = new List <XivMdl>(); var textureSets = new List <Dictionary <string, ModelTextureData> >(); foreach (var iItem in items) { try { var mdlData = mdl.GetRawMdlData(iItem, race).Result; if (mdlData != null) { mdlDatas.Add(mdlData); textureSets.Add(TexTools.MaterialsHelper.GetMaterials(_gameDir, item, mdlData, race).Result); continue; } } catch { } WriteLine($"Failed to get {iItem.Name}。 Got null."); if (items.Count > 1) { WriteLine($"{iItem.Name} has no components like {iItem.TertiaryCategory}."); } } try { var set = BatchExportSets(mdlDatas, textureSets); set.Name = TexTools.XivStringRaces.ToRaceGenderName(race); metadata.Sets.Add(set); } catch (NotImplementedException e) { } } if (metadata.Sets[0].Models.Count == 0) { WriteLine($"Empty model {item.Name}."); return; } var metadataJson = JsonConvert.SerializeObject(metadata); File.WriteAllText(path, metadataJson); WriteLine($"Exported {item.GetType().Name} {item.Name}: {Path.GetFileNameWithoutExtension(path)}"); }
public async Task AsyncInit() { var root = _item.GetRoot(); if (root == null) { return; } var gd = XivCache.GameInfo.GameDirectory; var lang = XivCache.GameInfo.GameLanguage; var df = IOUtil.GetDataFileFromPath(root.Info.GetRootFile()); var _index = new Index(gd); var _mtrl = new Mtrl(XivCache.GameInfo.GameDirectory); var _mdl = new Mdl(gd, df); var _imc = new Imc(gd); var raceRegex = new Regex("c([0-9]{4})[^b]"); ItemNameBox.Text = _item.Name; var setName = root.Info.GetBaseFileName(false); SetLabel.Text = "Set: " + setName; if (!String.IsNullOrWhiteSpace(root.Info.Slot)) { var niceSlot = Mdl.SlotAbbreviationDictionary.FirstOrDefault(x => x.Value == root.Info.Slot); if (niceSlot.Key != null) { SlotLabel.Text = "Slot: " + niceSlot.Key + " (" + root.Info.Slot + ")"; } else { SlotLabel.Text = "Slot: Unknown (" + root.Info.Slot + ")"; } } else { SlotLabel.Text = "Slot: --"; } var usesImc = Imc.UsesImc(_item); if (usesImc) { VariantLabel.Text = "Variant: " + _item.ModelInfo.ImcSubsetID; } else { VariantLabel.Text = "Variant: --"; } var mSet = await _imc.GetMaterialSetId(_item); if (mSet > 0) { MaterialSetLabel.Text = "Material Set: " + mSet; } else { MaterialSetLabel.Text = "Material Set: --"; } var races = XivRaces.PlayableRaces; var models = await root.GetModelFiles(); var materials = await root.GetMaterialFiles(mSet); #region Race Chart var rowIdx = 1; foreach (var race in races) { var rCode = race.GetRaceCode(); var row = new RowDefinition(); row.Height = new GridLength(30); RacialGrid.RowDefinitions.Add(row); var lBase = new Label(); lBase.Content = race.GetDisplayName(); lBase.SetValue(Grid.RowProperty, rowIdx); RacialGrid.Children.Add(lBase); XivRace?usedMdlRace = race; string usedMdl = null;; if (race != XivRace.All_Races) { // Check if the race has a model. var mdl = models.FirstOrDefault(x => x.Contains("c" + rCode)); if (mdl == null) { // Gotta see which race they're shared from. var node = XivRaceTree.GetNode(race); var parent = node.Parent; while (parent != null) { var code = parent.Race.GetRaceCode(); mdl = models.FirstOrDefault(x => x.Contains("c" + code)); if (mdl != null) { usedMdlRace = parent.Race; usedMdl = mdl; break; } parent = parent.Parent; } if (mdl == null) { // No model exists for this item. usedMdlRace = null; } } else { usedMdl = mdl; } } var mdlRaceString = "None"; if (usedMdlRace == race) { mdlRaceString = "Own"; } else { if (usedMdlRace != null) { mdlRaceString = ((XivRace)usedMdlRace).GetDisplayName(); } } XivRace?usedMtrlRace = usedMdlRace; if (race != XivRace.All_Races) { if (usedMdlRace == null) { usedMtrlRace = null; } else { // Get the materials used by this racial's model. var mdl = usedMdl; var mdlMaterials = await XivCache.GetChildFiles(mdl); var mtrl = mdlMaterials.FirstOrDefault(x => raceRegex.IsMatch(x)); if (mtrl == null) { usedMtrlRace = null; } else { var code = raceRegex.Match(mtrl).Groups[1].Value; usedMtrlRace = XivRaces.GetXivRace(code); if (usedMtrlRace == XivRace.All_Races) { usedMtrlRace = null; } } } } var mtrlRaceString = "None"; if (usedMtrlRace == race) { mtrlRaceString = "Own"; } else { if (usedMtrlRace != null) { mtrlRaceString = ((XivRace)usedMtrlRace).GetDisplayName(); } } var lMdl = new Label(); lMdl.Content = mdlRaceString; lMdl.SetValue(Grid.RowProperty, rowIdx); lMdl.SetValue(Grid.ColumnProperty, 1); RacialGrid.Children.Add(lMdl); var lMtrl = new Label(); lMtrl.Content = mtrlRaceString; lMtrl.SetValue(Grid.RowProperty, rowIdx); lMtrl.SetValue(Grid.ColumnProperty, 2); RacialGrid.Children.Add(lMtrl); rowIdx++; } #endregion if (Imc.UsesImc(_item) && _item.ModelInfo != null) { var myImcSubsetId = _item.ModelInfo.ImcSubsetID; var allItems = await root.GetAllItems(); var fInfo = await _imc.GetFullImcInfo(_item); var entries = fInfo.GetAllEntries(_item.GetItemSlotAbbreviation(), true); foreach (var item in allItems) { SameModelItems.Add(new KeyValuePair <string, IItem>(item.Name, item)); if (entries.Count > item.ModelInfo.ImcSubsetID) { var imSet = entries[item.ModelInfo.ImcSubsetID].MaterialSet; if (mSet == imSet) { SameMSetItems.Add(new KeyValuePair <string, IItem>(item.Name, item)); } } if (item.ModelInfo.ImcSubsetID == myImcSubsetId) { SameVariantItems.Add(new KeyValuePair <string, IItem>(item.Name, item)); } } } }
public ImportModelViewModel(ImportModelView view, IItemModel item, XivRace race, string submeshId, bool dataOnly, Action onComplete = null) { _view = view; _item = item; _race = race; _submeshId = submeshId; _dataOnly = dataOnly; _onComplete = onComplete; var gameDirectory = new DirectoryInfo(Settings.Default.FFXIV_Directory); var saveDirectory = new DirectoryInfo(Settings.Default.Save_Directory); var dataFile = IOUtil.GetDataFileFromPath(_item.GetItemRootFolder()); _mdl = new Mdl(gameDirectory, dataFile); _importers = _mdl.GetAvailableImporters(); // We need to explicitly fork this onto a new thread to avoid deadlock. Task.Run(AssignPath).Wait(); var defaultPath = $"{IOUtil.MakeItemSavePath(_item, saveDirectory, _race)}\\3D"; defaultPath = defaultPath.Replace("/", "\\"); var modelName = Path.GetFileNameWithoutExtension(_internalPath); // Scan to see which file type(s) actually exist. bool foundValidFile = false; // FBX is default, so check that first. var startingPath = Path.Combine(defaultPath, modelName) + ".fbx"; if (File.Exists(startingPath)) { foundValidFile = true; } if (!foundValidFile) { foreach (var suffix in _importers) { startingPath = Path.Combine(defaultPath, modelName) + "." + suffix; if (File.Exists(startingPath)) { foundValidFile = true; break; } } } if (!foundValidFile) { startingPath = ""; } _view.FileNameTextBox.Text = startingPath; // Event Handlers _view.SelectFileButton.Click += SelectFileButton_Click; _view.ImportButton.Click += ImportButton_Click; _view.EditButton.Click += EditButton_Click; _view.Closing += _view_Closing; // Default Settings for specific categories. if (item.SecondaryCategory == XivStrings.Face) { _view.EnableShapeDataButton.IsChecked = true; } if (item.SecondaryCategory == XivStrings.Hair) { _view.CloneUV1Button.IsChecked = true; } var iType = item.GetPrimaryItemType(); if (iType == xivModdingFramework.Items.Enums.XivItemType.equipment || iType == xivModdingFramework.Items.Enums.XivItemType.accessory || iType == xivModdingFramework.Items.Enums.XivItemType.weapon) { _view.ForceUVsButton.IsChecked = true; } }