public async Task <FullImcInfo> GetFullImcInfo(IItemModel item, IndexFile index = null, ModList modlist = null) { FullImcInfo info = null; try { var imcPath = GetImcPath(item); var path = imcPath.Folder + "/" + imcPath.File; info = await GetFullImcInfo(path, index, modlist); } catch { // Some dual wield items don't have a second IMC, and just default to the first. if (typeof(XivGear) == item.GetType()) { var gear = (XivGear)item; if (gear != null && gear.PairedItem != null) { var pair = gear.PairedItem; var imcPath = GetImcPath(pair); var path = imcPath.Folder + "/" + imcPath.File; return(await(GetFullImcInfo(path, index, modlist))); } } else { throw new InvalidDataException("Unable to get IMC data for item: " + item.Name); } } return(info); }
public async Task SaveFullImcInfo(FullImcInfo info, string path, string itemName = null, string category = null, string source = null) { var index = new Index(_gameDirectory); var dat = new Dat(_gameDirectory); var imcOffset = await index.GetDataOffset(path); // No writing new IMC files. if (imcOffset == 0) { throw new InvalidDataException($"Could not find offset for {path}"); } var data = new List <byte>(); // 4 Header bytes. data.AddRange(BitConverter.GetBytes((short)info.SubsetCount)); data.AddRange(BitConverter.GetBytes((short)info.TypeIdentifier)); // The rest of this is easy, it's literally just post all the sets in order. foreach (var entry in info.DefaultSubset) { data.AddRange(entry.GetBytes()); } foreach (var set in info.SubsetList) { foreach (var entry in set) { data.AddRange(entry.GetBytes()); } } // That's it. // Get outta here with your fancy operators //itemName ??= Path.GetFileName(path); //category ??= "Meta"; //source ??= "Internal"; itemName = itemName ?? Path.GetFileName(path); category = category ?? "Meta"; source = source ?? "Internal"; await dat.ImportType2Data(data.ToArray(), itemName, path, category, source); }
public async Task SaveFullImcInfo(FullImcInfo info, IItemModel item) { try { var imcPath = GetImcPath(item); var path = imcPath.Folder + "/" + imcPath.File; await SaveFullImcInfo(info, path); } catch { // Some dual wield items don't have a second IMC, and just default to the first. var gear = (XivGear)item; if (gear != null && gear.PairedItem != null) { var pair = gear.PairedItem; var imcPath = GetImcPath(pair); var path = imcPath.Folder + "/" + imcPath.File; await(SaveFullImcInfo(info, path)); } } return; }
public async Task <FullImcInfo> GetFullImcInfo(IItemModel item) { FullImcInfo info = null; try { var imcPath = GetImcPath(item); var path = imcPath.Folder + "/" + imcPath.File; info = await GetFullImcInfo(path); } catch { // Some dual wield items don't have a second IMC, and just default to the first. var gear = (XivGear)item; if (gear != null && gear.PairedItem != null) { var pair = gear.PairedItem; var imcPath = GetImcPath(pair); var path = imcPath.Folder + "/" + imcPath.File; return(await(GetFullImcInfo(path))); } } return(info); }
public async Task SaveFullImcInfo(FullImcInfo info, string path, string source, IItem referenceItem = null, IndexFile cachedIndexFile = null, ModList cachedModList = null) { if (info == null || info.TypeIdentifier != ImcType.Set && info.TypeIdentifier != ImcType.NonSet) { throw new InvalidDataException("Cannot save invalid IMC file."); } var index = new Index(_gameDirectory); var dat = new Dat(_gameDirectory); var data = new List <byte>(); // 4 Header bytes. data.AddRange(BitConverter.GetBytes((short)info.SubsetCount)); data.AddRange(BitConverter.GetBytes((short)info.TypeIdentifier)); // The rest of this is easy, it's literally just post all the sets in order. foreach (var entry in info.DefaultSubset) { data.AddRange(entry.GetBytes(info.TypeIdentifier)); } foreach (var set in info.SubsetList) { foreach (var entry in set) { data.AddRange(entry.GetBytes(info.TypeIdentifier)); } } // That's it. source ??= "Unknown"; await dat.ImportType2Data(data.ToArray(), path, source, referenceItem, cachedIndexFile, cachedModList); }
/// <summary> /// Gets the full IMC information for a given item /// </summary> /// <param name="item"></param> /// <param name="useSecondary">Determines if the SecondaryModelInfo should be used instead.(XivGear only)</param> /// <returns>The ImcData data</returns> public async Task <FullImcInfo> GetFullImcInfo(string path) { var index = new Index(_gameDirectory); var dat = new Dat(_gameDirectory); var imcOffset = await index.GetDataOffset(path); if (imcOffset == 0) { throw new InvalidDataException($"Could not find offset for {path}"); } var imcByteData = await dat.GetType2Data(imcOffset, IOUtil.GetDataFileFromPath(path)); return(await Task.Run(() => { using (var br = new BinaryReader(new MemoryStream(imcByteData))) { var subsetCount = br.ReadInt16(); var identifier = br.ReadInt16(); var imcData = new FullImcInfo() { TypeIdentifier = (ImcType)identifier, DefaultSubset = new List <XivImc>(), SubsetList = new List <List <XivImc> >(subsetCount) }; //weapons and monsters do not have variant sets if (imcData.TypeIdentifier == ImcType.NonSet) { // This type uses the first short for both Variant and VFX. byte variant = br.ReadByte(); byte unknown = br.ReadByte(); ushort mask = br.ReadUInt16(); ushort vfx = br.ReadUInt16(); imcData.DefaultSubset.Add(new XivImc { Variant = variant, Unknown = unknown, Mask = mask, Vfx = variant }); for (var i = 0; i < subsetCount; i++) { variant = br.ReadByte(); unknown = br.ReadByte(); mask = br.ReadUInt16(); vfx = br.ReadUInt16(); var newEntry = new XivImc { Variant = variant, Unknown = unknown, Mask = mask, Vfx = vfx }; var subset = new List <XivImc>() { newEntry }; imcData.SubsetList.Add(subset); } } else if (imcData.TypeIdentifier == ImcType.Set) { // Identifier used by Equipment. imcData.DefaultSubset = new List <XivImc>() { new XivImc { Variant = br.ReadByte(), Unknown = br.ReadByte(), Mask = br.ReadUInt16(), Vfx = br.ReadUInt16() }, new XivImc { Variant = br.ReadByte(), Unknown = br.ReadByte(), Mask = br.ReadUInt16(), Vfx = br.ReadUInt16() }, new XivImc { Variant = br.ReadByte(), Unknown = br.ReadByte(), Mask = br.ReadUInt16(), Vfx = br.ReadUInt16() }, new XivImc { Variant = br.ReadByte(), Unknown = br.ReadByte(), Mask = br.ReadUInt16(), Vfx = br.ReadUInt16() }, new XivImc { Variant = br.ReadByte(), Unknown = br.ReadByte(), Mask = br.ReadUInt16(), Vfx = br.ReadUInt16() }, }; for (var i = 0; i < subsetCount; i++) { // gets the data for each slot in the current variant set var imcGear = new List <XivImc>() { new XivImc { Variant = br.ReadByte(), Unknown = br.ReadByte(), Mask = br.ReadUInt16(), Vfx = br.ReadUInt16() }, new XivImc { Variant = br.ReadByte(), Unknown = br.ReadByte(), Mask = br.ReadUInt16(), Vfx = br.ReadUInt16() }, new XivImc { Variant = br.ReadByte(), Unknown = br.ReadByte(), Mask = br.ReadUInt16(), Vfx = br.ReadUInt16() }, new XivImc { Variant = br.ReadByte(), Unknown = br.ReadByte(), Mask = br.ReadUInt16(), Vfx = br.ReadUInt16() }, new XivImc { Variant = br.ReadByte(), Unknown = br.ReadByte(), Mask = br.ReadUInt16(), Vfx = br.ReadUInt16() }, }; imcData.SubsetList.Add(imcGear); } } else { throw new NotSupportedException("Unknown IMC Type Identifier. (Please report this item in the TexTools Discord #bug_reports channel.)"); } return imcData; } })); }
/// <summary> /// Updates the View/ViewModel with a new selected base item. /// </summary> /// <param name="item"></param> /// <returns></returns> public async Task <bool> SetItem(IItem item, MainWindow mainWindow = null) { var gameDirectory = new DirectoryInfo(Properties.Settings.Default.FFXIV_Directory); _imc = new Imc(gameDirectory, item.DataFile); _gear = new Gear(gameDirectory, XivLanguages.GetXivLanguage(Properties.Settings.Default.Application_Language)); if (mainWindow != null) { _mainWindow = mainWindow; } _item = item; _tree.Items.Clear(); IItemModel im = null; try { im = (IItemModel)item; } catch (Exception ex) { return(false); } if (im == null || im.ModelInfo == null) { return(false); } var topLevelItem = new TreeViewItem(); topLevelItem.Header = ""; if (im.ModelInfo.PrimaryID > 0) { topLevelItem.Header += CapFirst(item.GetPrimaryItemType().ToString()) + " #" + im.ModelInfo.PrimaryID.ToString().PadLeft(4, '0'); } else { topLevelItem.Header += CapFirst(item.GetPrimaryItemType().ToString()); } _tree.Items.Add(topLevelItem); var nextParent = topLevelItem; if (im.ModelInfo.SecondaryID > 0) { var nextNode = new TreeViewItem(); nextNode.Header += CapFirst(item.GetSecondaryItemType().ToString()) + " #" + im.ModelInfo.SecondaryID.ToString().PadLeft(4, '0'); nextParent.Items.Add(nextNode); nextParent.IsExpanded = true; nextParent = nextNode; } var abbreviation = _item.GetItemSlotAbbreviation(); if (abbreviation != "") { var nextNode = new TreeViewItem(); nextNode.Header = Mdl.SlotAbbreviationDictionary.First(x => x.Value == abbreviation).Key; nextParent.Items.Add(nextNode); nextParent.IsExpanded = true; nextParent = nextNode; } FullImcInfo fullInfo = null; try { fullInfo = await _imc.GetFullImcInfo(im); } catch (Exception ex) { // This item has no IMC file. var nextNode = new TreeViewItem(); nextNode.Header = im.Name; nextNode.DataContext = im; //nextNode.MouseDoubleClick += ItemNode_Activated; nextParent.Items.Add(nextNode); nextParent.IsExpanded = true; nextNode.IsSelected = true; nextParent = nextNode; // No shared items for things without IMC files, so just hide the view entirely? return(false); } var sharedList = await _gear.GetSameModelList(im); var myVariantNumber = fullInfo.GetEntry(im.ModelInfo.ImcSubsetID, im.GetItemSlotAbbreviation()).Variant; var myImcNumber = im.ModelInfo.ImcSubsetID; var materialVariantHeaders = new Dictionary <int, TreeViewItem>(); var imcVariantHeaders = new Dictionary <int, TreeViewItem>(); // TODO - // Add the Variant header nodes at the start, and only scan the IMC files when a TreeViewItem myMaterialHeader = null; TreeViewItem myImcHeader = null; TreeViewItem myNode = null; foreach (var i in sharedList) { // Get the Variant # information var info = fullInfo.GetEntry(i.ModelInfo.ImcSubsetID, i.GetItemSlotAbbreviation()); if (info == null) { // Invalid IMC Set ID for the item. continue; } if (!materialVariantHeaders.ContainsKey(info.Variant)) { materialVariantHeaders.Add(info.Variant, new TreeViewItem()); materialVariantHeaders[info.Variant].Header = "Material Variant #" + info.Variant; materialVariantHeaders[info.Variant].DataContext = info.Variant; } if (!imcVariantHeaders.ContainsKey(i.ModelInfo.ImcSubsetID)) { imcVariantHeaders.Add(i.ModelInfo.ImcSubsetID, new TreeViewItem()); imcVariantHeaders[i.ModelInfo.ImcSubsetID].Header = "IMC Variant #" + i.ModelInfo.ImcSubsetID; imcVariantHeaders[i.ModelInfo.ImcSubsetID].DataContext = i.ModelInfo.ImcSubsetID; var hiddenParts = MaskToHidenParts(info.Mask); imcVariantHeaders[i.ModelInfo.ImcSubsetID].Header += " - Hidden Parts: "; if (hiddenParts.Count > 0) { imcVariantHeaders[i.ModelInfo.ImcSubsetID].Header += String.Join(",", hiddenParts); } else { imcVariantHeaders[i.ModelInfo.ImcSubsetID].Header += "None"; } materialVariantHeaders[info.Variant].Items.Add(imcVariantHeaders[i.ModelInfo.ImcSubsetID]); if (i.ModelInfo.ImcSubsetID == myImcNumber) { myImcHeader = imcVariantHeaders[i.ModelInfo.ImcSubsetID]; } } var nextNode = new TreeViewItem(); nextNode.Header = i.Name; nextNode.DataContext = i; imcVariantHeaders[i.ModelInfo.ImcSubsetID].Items.Add(nextNode); if (myMaterialHeader == null && info.Variant == myVariantNumber) { myMaterialHeader = materialVariantHeaders[info.Variant]; } if (i.Name == im.Name) { myNode = nextNode; } else { nextNode.MouseDoubleClick += ItemNode_Activated; } } var ordered = materialVariantHeaders.OrderBy(x => x.Key); foreach (var kv in ordered) { nextParent.Items.Add(kv.Value); } nextParent.IsExpanded = true; if (myMaterialHeader != null) { myMaterialHeader.IsExpanded = true; } if (myImcHeader != null) { myImcHeader.IsExpanded = true; } if (myNode != null) { myNode.IsSelected = true; } return(true); }
/// <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); }