/// <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); } }