private async void ImportButton_Click(object sender, RoutedEventArgs e) { var path = PathBox.Text; if (String.IsNullOrWhiteSpace(path)) { return; } var od = new OpenFileDialog(); var result = od.ShowDialog(); if (result != System.Windows.Forms.DialogResult.OK) { return; } byte[] data = null; var _dat = new Dat(XivCache.GameInfo.GameDirectory); var _index = new Index(XivCache.GameInfo.GameDirectory); if (DecompressedType2.IsChecked == true) { var temp = File.ReadAllBytes(od.FileName); data = await _dat.CreateType2Data(temp); } else { data = File.ReadAllBytes(od.FileName); } var type = BitConverter.ToInt32(data, 4); if (type < 2 || type > 4) { FlexibleMessageBox.Show("Invalid Data Type.\nGeneric binary files should be imported as decompressed type 2 Data.", "Data Type Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } try { var dummyItem = new XivGenericItemModel(); dummyItem.Name = Path.GetFileName(path); dummyItem.SecondaryCategory = "Raw File Imports"; await _dat.WriteModFile(data, path, XivStrings.TexTools, dummyItem); } catch (Exception Ex) { FlexibleMessageBox.Show("Unable to import file.\n\nError: " + Ex.Message, "Import Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } FlexibleMessageBox.Show("File Imported Successfully.", "Import Success", MessageBoxButtons.OK, MessageBoxIcon.Information); this.Close(); }
private static async Task SaveCharaMakeParameterSet(CharaMakeParameterSet cmp, IndexFile index = null, ModList modlist = null) { var _dat = new Dat(XivCache.GameInfo.GameDirectory); var dummyItem = new XivGenericItemModel(); dummyItem.Name = "human.cmp"; dummyItem.SecondaryCategory = Constants.InternalModSourceName; await _dat.ImportType2Data(cmp.GetBytes(), HumanCmpPath, Constants.InternalModSourceName, dummyItem, index, modlist); }
public static async Task SaveStainingTemplateFile(StainingTemplateFile file, string applicationSource, IndexFile index = null, ModList modlist = null) { throw new NotImplementedException(); var data = new byte[0];//file.GetBytes(); var _dat = new Dat(XivCache.GameInfo.GameDirectory); var dummyItem = new XivGenericItemModel() { Name = "Equipment Staining Template", SecondaryCategory = "Raw Files" }; await _dat.ImportType2Data(data, GearStainingTemplatePath, applicationSource, null, index, modlist); }
/// <summary> /// Saves a racial scaling entry to file. /// </summary> /// <param name="rgsp"></param> /// <param name=""></param> /// <returns></returns> public static async Task SaveScalingParameter(RacialGenderScalingParameter rgsp, string sourceApplication, IndexFile index = null, ModList modlist = null) { // Write the .rgsp file and let the DAT functions handle applying it. var rgspFilePath = GetRgspPath(rgsp.Race, rgsp.Gender); var bytes = rgsp.GetBytes(); var dummyItem = new XivGenericItemModel(); dummyItem.Name = rgsp.Race.GetDisplayName() + " - " + rgsp.Gender.ToString(); dummyItem.SecondaryCategory = "Racial Scaling"; var _dat = new Dat(XivCache.GameInfo.GameDirectory); await _dat.ImportType2Data(bytes, rgspFilePath, sourceApplication, dummyItem, index, modlist); }
/// <summary> /// Makes a generic item model from the mod item /// </summary> /// <param name="modItem">The mod item</param> /// <returns>The mod item as a XivGenericItemModel</returns> private static XivGenericItemModel MakeItemModel(Mod modItem) { var fullPath = modItem.fullPath; var item = new XivGenericItemModel { Name = modItem.name, ItemCategory = modItem.category, DataFile = XivDataFiles.GetXivDataFile(modItem.datFile) }; if (modItem.fullPath.Contains("chara/equipment") || modItem.fullPath.Contains("chara/accessory")) { item.Category = XivStrings.Gear; item.ModelInfo = new XivModelInfo { ModelID = int.Parse(fullPath.Substring(17, 4)) }; } if (modItem.fullPath.Contains("chara/weapon")) { item.Category = XivStrings.Gear; item.ModelInfo = new XivModelInfo { ModelID = int.Parse(fullPath.Substring(14, 4)) }; } if (modItem.fullPath.Contains("chara/human")) { item.Category = XivStrings.Character; if (item.Name.Equals(XivStrings.Body)) { item.ModelInfo = new XivModelInfo { ModelID = int.Parse(fullPath.Substring(fullPath.IndexOf("/body", StringComparison.Ordinal) + 7, 4)) }; } else if (item.Name.Equals(XivStrings.Hair)) { item.ModelInfo = new XivModelInfo { ModelID = int.Parse(fullPath.Substring(fullPath.IndexOf("/hair", StringComparison.Ordinal) + 7, 4)) }; } else if (item.Name.Equals(XivStrings.Face)) { item.ModelInfo = new XivModelInfo { ModelID = int.Parse(fullPath.Substring(fullPath.IndexOf("/face", StringComparison.Ordinal) + 7, 4)) }; } else if (item.Name.Equals(XivStrings.Tail)) { item.ModelInfo = new XivModelInfo { ModelID = int.Parse(fullPath.Substring(fullPath.IndexOf("/tail", StringComparison.Ordinal) + 7, 4)) }; } } if (modItem.fullPath.Contains("chara/common")) { item.Category = XivStrings.Character; if (item.Name.Equals(XivStrings.Face_Paint)) { item.ModelInfo = new XivModelInfo { ModelID = int.Parse(fullPath.Substring(fullPath.LastIndexOf("_", StringComparison.Ordinal) + 1, 1)) }; } else if (item.Name.Equals(XivStrings.Equip_Decals)) { item.ModelInfo = new XivModelInfo { ModelID = int.Parse(fullPath.Substring(fullPath.LastIndexOf("_", StringComparison.Ordinal) + 1, 3)) }; } } if (modItem.fullPath.Contains("chara/monster")) { item.Category = XivStrings.Companions; item.ModelInfo = new XivModelInfo { ModelID = int.Parse(fullPath.Substring(15, 4)), Body = int.Parse(fullPath.Substring(fullPath.IndexOf("/body", StringComparison.Ordinal) + 7, 4)) }; } if (modItem.fullPath.Contains("chara/demihuman")) { item.Category = XivStrings.Companions; item.ModelInfo = new XivModelInfo { Body = int.Parse(fullPath.Substring(17, 4)), ModelID = int.Parse(fullPath.Substring(fullPath.IndexOf("t/e", StringComparison.Ordinal) + 3, 4)) }; } if (modItem.fullPath.Contains("ui/")) { item.Category = XivStrings.UI; if (modItem.fullPath.Contains("ui/uld") || modItem.fullPath.Contains("ui/map")) { item.ModelInfo = new XivModelInfo { ModelID = 0 }; } else { item.ModelInfo = new XivModelInfo { ModelID = int.Parse(fullPath.Substring(fullPath.LastIndexOf("/", StringComparison.Ordinal) + 1, 6)) }; } } if (modItem.fullPath.Contains("/hou/")) { item.Category = XivStrings.Housing; item.ModelInfo = new XivModelInfo { ModelID = int.Parse(fullPath.Substring(fullPath.LastIndexOf("_m", StringComparison.Ordinal) + 2, 3)) }; } return(item); }
/// <summary> /// Gets the materials for the model /// </summary> /// <returns>A dictionary containing the mesh number(key) and the associated texture data (value)</returns> public static Dictionary <int, ModelTextureData> GetMaterials( DirectoryInfo gameDirectory, IItemModel item, XivMdl mdlData, XivRace race) { var textureDataDictionary = new Dictionary <int, ModelTextureData>(); var mtrlDictionary = new Dictionary <int, XivMtrl>(); var mtrl = new Mtrl(gameDirectory, item.DataFile); var mtrlFilePaths = mdlData.PathData.MaterialList; var hasColorChangeShader = false; Color? customColor = null; WinColor winColor; var materialNum = 0; foreach (var mtrlFilePath in mtrlFilePaths) { var mtrlItem = new XivGenericItemModel { Category = item.Category, ItemCategory = item.ItemCategory, ItemSubCategory = item.ItemSubCategory, ModelInfo = new XivModelInfo { Body = item.ModelInfo.Body, ModelID = item.ModelInfo.ModelID, ModelType = item.ModelInfo.ModelType, Variant = item.ModelInfo.Variant }, Name = item.Name }; var modelID = mtrlItem.ModelInfo.ModelID; var bodyID = mtrlItem.ModelInfo.Body; var filePath = mtrlFilePath; if (!filePath.Contains("hou") && mtrlFilePath.Count(x => x == '/') > 1) { filePath = mtrlFilePath.Substring(mtrlFilePath.LastIndexOf("/")); } var typeChar = $"{mtrlFilePath[4]}{mtrlFilePath[9]}"; var raceString = ""; switch (typeChar) { // Character Body case "cb": var body = mtrlFilePath.Substring(mtrlFilePath.IndexOf("b") + 1, 4); raceString = mtrlFilePath.Substring(mtrlFilePath.IndexOf("c") + 1, 4); race = XivRaces.GetXivRace(raceString); if (!raceString.Equals("0901") && !raceString.Equals("1001") && !raceString.Equals("1101")) { var gender = 0; if (int.Parse(raceString.Substring(0, 2)) % 2 == 0) { gender = 1; } var settingsRace = GetSettingsRace(gender); race = settingsRace.Race; filePath = mtrlFilePath.Replace(raceString, race.GetRaceCode()).Replace(body, settingsRace.BodyID); body = settingsRace.BodyID; } mtrlItem = new XivGenericItemModel { Category = XivStrings.Character, ItemCategory = XivStrings.Body, Name = XivStrings.Body, ModelInfo = new XivModelInfo { Body = int.Parse(body) } }; winColor = (WinColor)ColorConverter.ConvertFromString(Settings.Default.Skin_Color); customColor = new Color(winColor.R, winColor.G, winColor.B, winColor.A); break; // Face case "cf": bodyID = int.Parse(mtrlFilePath.Substring(mtrlFilePath.IndexOf("f") + 1, 4)); raceString = mtrlFilePath.Substring(mtrlFilePath.IndexOf("c") + 1, 4); race = XivRaces.GetXivRace(raceString); mtrlItem = new XivGenericItemModel { Category = XivStrings.Character, ItemCategory = XivStrings.Face, Name = XivStrings.Face, ModelInfo = new XivModelInfo { Body = bodyID } }; break; // Hair case "ch": bodyID = int.Parse(mtrlFilePath.Substring(mtrlFilePath.IndexOf("h") + 1, 4)); raceString = mtrlFilePath.Substring(mtrlFilePath.IndexOf("c") + 1, 4); race = XivRaces.GetXivRace(raceString); mtrlItem = new XivGenericItemModel { Category = XivStrings.Character, ItemCategory = XivStrings.Hair, Name = XivStrings.Hair, ModelInfo = new XivModelInfo { Body = bodyID } }; winColor = (WinColor)ColorConverter.ConvertFromString(Settings.Default.Hair_Color); customColor = new Color(winColor.R, winColor.G, winColor.B, winColor.A); break; // Tail case "ct": var tempPath = mtrlFilePath.Substring(4); bodyID = int.Parse(tempPath.Substring(tempPath.IndexOf("t") + 1, 4)); raceString = mtrlFilePath.Substring(mtrlFilePath.IndexOf("c") + 1, 4); race = XivRaces.GetXivRace(raceString); mtrlItem = new XivGenericItemModel { Category = XivStrings.Character, ItemCategory = XivStrings.Tail, Name = XivStrings.Tail, ModelInfo = new XivModelInfo { Body = bodyID } }; winColor = (WinColor)ColorConverter.ConvertFromString(Settings.Default.Hair_Color); customColor = new Color(winColor.R, winColor.G, winColor.B, winColor.A); break; // Equipment case "ce": modelID = int.Parse(mtrlFilePath.Substring(mtrlFilePath.IndexOf("e") + 1, 4)); raceString = mtrlFilePath.Substring(mtrlFilePath.IndexOf("c") + 1, 4); race = XivRaces.GetXivRace(raceString); mtrlItem.ModelInfo.ModelID = modelID; break; // Accessory case "ca": modelID = int.Parse(mtrlFilePath.Substring(mtrlFilePath.IndexOf("a") + 1, 4)); raceString = mtrlFilePath.Substring(mtrlFilePath.IndexOf("c") + 1, 4); race = XivRaces.GetXivRace(raceString); mtrlItem.ModelInfo.ModelID = modelID; break; // Weapon case "wb": modelID = int.Parse(mtrlFilePath.Substring(mtrlFilePath.IndexOf("w") + 1, 4)); bodyID = int.Parse(mtrlFilePath.Substring(mtrlFilePath.IndexOf("b") + 1, 4)); mtrlItem.ModelInfo.ModelID = modelID; mtrlItem.ModelInfo.Body = bodyID; break; // Monster case "mb": modelID = int.Parse(mtrlFilePath.Substring(mtrlFilePath.IndexOf("_m") + 2, 4)); bodyID = int.Parse(mtrlFilePath.Substring(mtrlFilePath.IndexOf("b") + 1, 4)); mtrlItem.ModelInfo.ModelID = modelID; mtrlItem.ModelInfo.Body = bodyID; break; // DemiHuman case "de": modelID = int.Parse(mtrlFilePath.Substring(mtrlFilePath.IndexOf("d") + 1, 4)); bodyID = int.Parse(mtrlFilePath.Substring(mtrlFilePath.IndexOf("e") + 1, 4)); mtrlItem.ModelInfo.ModelID = modelID; mtrlItem.ModelInfo.Body = bodyID; break; default: break; } var dxVersion = int.Parse(Settings.Default.DX_Version); var mtrlFile = filePath.Remove(0, 1); XivMtrl mtrlData; try { mtrlData = mtrl.GetMtrlData(mtrlItem, race, mtrlFile, dxVersion); } catch (Exception) { if (mtrlItem.ModelInfo.ModelID == item.ModelInfo.ModelID) { throw; } // Fall back to material data from the primary model. mtrlData = mtrl.GetMtrlData(item, race, mtrlFile, dxVersion); } if (mtrlData.Shader.Contains("colorchange")) { hasColorChangeShader = true; } mtrlDictionary.Add(materialNum, mtrlData); materialNum++; } foreach (var xivMtrl in mtrlDictionary) { var modelTexture = new ModelTexture(gameDirectory, xivMtrl.Value); if (hasColorChangeShader) { var modelMaps = modelTexture.GetModelMaps(null, true); textureDataDictionary.Add(xivMtrl.Key, modelMaps); } else { if (item.ItemCategory.Equals(XivStrings.Face)) { var path = xivMtrl.Value.MTRLPath; if (path.Contains("_iri_")) { winColor = (WinColor)ColorConverter.ConvertFromString(Settings.Default.Iris_Color); } else if (path.Contains("_etc_")) { winColor = (WinColor)ColorConverter.ConvertFromString(Settings.Default.Etc_Color); } else { winColor = (WinColor)ColorConverter.ConvertFromString(Settings.Default.Skin_Color); } customColor = new Color(winColor.R, winColor.G, winColor.B, winColor.A); } var modelMaps = modelTexture.GetModelMaps(customColor); textureDataDictionary.Add(xivMtrl.Key, modelMaps); } } return(textureDataDictionary); }
/// <summary> /// Applies this Metadata object to the FFXIV file system. /// This should only called by Dat.WriteToDat() / RestoreDefaultMetadata() /// </summary> internal static async Task ApplyMetadata(ItemMetadata meta, IndexFile index = null, ModList modlist = null) { var _eqp = new Eqp(XivCache.GameInfo.GameDirectory); var _modding = new Modding(XivCache.GameInfo.GameDirectory); var _index = new Index(XivCache.GameInfo.GameDirectory); var df = IOUtil.GetDataFileFromPath(meta.Root.Info.GetRootFile()); var dummyItem = new XivGenericItemModel(); dummyItem.Name = Constants.InternalModSourceName; dummyItem.SecondaryCategory = Constants.InternalModSourceName; // Beep boop bool doSave = false; if (index == null) { doSave = true; index = await _index.GetIndexFile(df); modlist = await _modding.GetModListAsync(); } if (meta.ImcEntries.Count > 0) { var _imc = new Imc(XivCache.GameInfo.GameDirectory); var imcPath = meta.Root.GetRawImcFilePath(); await _imc.SaveEntries(imcPath, meta.Root.Info.Slot, meta.ImcEntries, dummyItem, index, modlist); } // Applying EQP data via set 0 is not allowed, as it is a special set hard-coded to use Set 1's data. if (meta.EqpEntry != null && !(meta.Root.Info.PrimaryType == Items.Enums.XivItemType.equipment && meta.Root.Info.PrimaryId == 0)) { await _eqp.SaveEqpEntry(meta.Root.Info.PrimaryId, meta.EqpEntry, dummyItem, index, modlist); } if (meta.EqdpEntries.Count > 0) { await _eqp.SaveEqdpEntries((uint)meta.Root.Info.PrimaryId, meta.Root.Info.Slot, meta.EqdpEntries, dummyItem, index, modlist); } if (meta.EstEntries.Count > 0) { var type = Est.GetEstType(meta.Root); var entries = meta.EstEntries.Values.ToList(); await Est.SaveExtraSkeletonEntries(type, entries, dummyItem, index, modlist); } if (meta.GmpEntry != null) { await _eqp.SaveGimmickParameter(meta.Root.Info.PrimaryId, meta.GmpEntry, dummyItem, index, modlist); } if (doSave) { await _index.SaveIndexFile(index); await _modding.SaveModListAsync(modlist); } }
/// <summary> /// Applies multiple metadata mods simultaneously for performance gains. /// </summary> /// <param name="data"></param> /// <param name="index"></param> /// <param name="modlist"></param> /// <returns></returns> internal static async Task ApplyMetadataBatched(List <ItemMetadata> data, IndexFile index, ModList modlist, bool save = true) { if (data == null || data.Count == 0) { return; } var _eqp = new Eqp(XivCache.GameInfo.GameDirectory); var _modding = new Modding(XivCache.GameInfo.GameDirectory); var _index = new Index(XivCache.GameInfo.GameDirectory); var dummyItem = new XivGenericItemModel(); dummyItem.Name = Constants.InternalModSourceName; dummyItem.SecondaryCategory = Constants.InternalModSourceName; Dictionary <XivRace, List <(uint PrimaryId, string Slot, EquipmentDeformationParameter Entry)> > eqdpEntries = new Dictionary <XivRace, List <(uint PrimaryId, string Slot, EquipmentDeformationParameter Entry)> >(); Dictionary <Est.EstType, List <ExtraSkeletonEntry> > estEntries = new Dictionary <Est.EstType, List <ExtraSkeletonEntry> >(); List <(uint PrimaryId, EquipmentParameter EqpData)> eqpEntries = new List <(uint PrimaryId, EquipmentParameter EqpData)>(); List <(uint PrimaryId, GimmickParameter GmpData)> gmpEntries = new List <(uint PrimaryId, GimmickParameter GmpData)>(); foreach (var meta in data) { // Construct the parameter collections for each function call. foreach (var kv in meta.EqdpEntries) { if (!eqdpEntries.ContainsKey(kv.Key)) { eqdpEntries.Add(kv.Key, new List <(uint PrimaryId, string Slot, EquipmentDeformationParameter Entry)>()); } eqdpEntries[kv.Key].Add(((uint)meta.Root.Info.PrimaryId, meta.Root.Info.Slot, kv.Value)); } var estType = Est.GetEstType(meta.Root); foreach (var kv in meta.EstEntries) { if (!estEntries.ContainsKey(estType)) { estEntries.Add(estType, new List <ExtraSkeletonEntry>()); } estEntries[estType].Add(kv.Value); } if (meta.EqpEntry != null) { eqpEntries.Add(((uint)meta.Root.Info.PrimaryId, meta.EqpEntry)); } if (meta.GmpEntry != null) { gmpEntries.Add(((uint)meta.Root.Info.PrimaryId, meta.GmpEntry)); } } if (index.DataFile == XivDataFile._04_Chara) { // Batch install functions for these three. await _eqp.SaveEqpEntries(eqpEntries, dummyItem, index, modlist); await _eqp.SaveEqdpEntries(eqdpEntries, dummyItem, index, modlist); await _eqp.SaveGmpEntries(gmpEntries, dummyItem, index, modlist); // The EST function already does batch applications by nature of how it works, // so just call it once for each of the four EST types represented. foreach (var kv in estEntries) { await Est.SaveExtraSkeletonEntries(kv.Key, kv.Value, dummyItem, index, modlist); } } // IMC Files don't really overlap that often, so it's // not a significant loss generally to just write them individually. foreach (var meta in data) { if (meta.ImcEntries.Count > 0) { var _imc = new Imc(XivCache.GameInfo.GameDirectory); var imcPath = meta.Root.GetRawImcFilePath(); await _imc.SaveEntries(imcPath, meta.Root.Info.Slot, meta.ImcEntries, null, index, modlist); } } if (save) { await _index.SaveIndexFile(index); await _modding.SaveModListAsync(modlist); } }