public async Task DisableMod() { _view.SaveButton.IsEnabled = false; _view.CancelButton.IsEnabled = false; _view.DisableButton.IsEnabled = false; _view.DisableButton.Content = UIStrings.Working_Ellipsis; var files = new List <string>(); // If we're disabling from the Edit Multi menu, diable all variant versions as well. if (_mode == MaterialEditorMode.EditMulti) { var sameModelItems = await _item.GetSharedModelItems(); var itemType = ItemType.GetPrimaryItemType(_item); // Find all the variant materials foreach (var item in sameModelItems) { var variantPath = await _mtrl.GetMtrlPath(item, _material.GetRace(), _material.GetMaterialIdentifier(), itemType); files.Add(variantPath.Folder + "/" + variantPath.File); } } else { // Just disabling this one. files.Add(_material.MTRLPath); } files = files.Distinct().ToList(); foreach (var file in files) { var modEntry = await _modding.TryGetModEntry(file); if (!modEntry.enabled) { continue; } // If the file is a custom addition, and not a modification. if (modEntry.source != XivStrings.TexTools) { await _modding.DeleteMod(file); } else { await _modding.ToggleModStatus(file, false); } } _view.Close(false); }
/// <summary> /// Gets the atex paths for a given item /// </summary> /// <param name="itemModel">The item to get the atex paths for</param> /// <returns>A list of TexTypePath containing the atex info</returns> public async Task <List <TexTypePath> > GetAtexPaths(IItemModel itemModel) { // Gear is the only type we know how to retrieve atex information for. if (itemModel.GetType() != typeof(XivGear)) { return(new List <TexTypePath>()); } var itemType = ItemType.GetPrimaryItemType(itemModel); var vfxPath = await GetVfxPath(itemModel); return(await GetAtexPaths(vfxPath.Folder + '/' + vfxPath.File)); }
/// <summary> /// Gets the atex paths for a given item /// </summary> /// <param name="itemModel">The item to get the atex paths for</param> /// <returns>A list of TexTypePath containing the atex info</returns> public async Task <List <TexTypePath> > GetAtexPaths(IItemModel itemModel) { var atexTexTypePathList = new List <TexTypePath>(); var index = new Index(_gameDirectory); var avfx = new Avfx(_gameDirectory, _dataFile); var itemType = ItemType.GetPrimaryItemType(itemModel); var vfxPath = await GetVfxPath(itemModel, itemType); var vfxOffset = await index.GetDataOffset(HashGenerator.GetHash(vfxPath.Folder), HashGenerator.GetHash(vfxPath.File), _dataFile); if (vfxOffset == 0) { throw new Exception($"Could not find offset for vfx path {vfxPath.Folder}/{vfxPath.File}"); } var aTexPaths = new List <string>(); try { aTexPaths = await avfx.GetATexPaths(vfxOffset); } catch (Exception e) { throw new Exception(e.Message); } foreach (var atexPath in aTexPaths) { var ttp = new TexTypePath { DataFile = _dataFile, Name = "VFX: " + Path.GetFileNameWithoutExtension(atexPath), Path = atexPath }; atexTexTypePathList.Add(ttp); } return(atexTexTypePathList); }
public async Task SaveMulti() { // 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(); // 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"; // Load and modify all the MTRLs. foreach (var item in sameModelItems) { // Resolve this item's material variant. // - This isn't always the same as the item model variant, for some reason. // - So it has to be resolved manually. var variantMtrlPath = ""; var itemType = ItemType.GetPrimaryItemType(_item); variantMtrlPath = (await _mtrl.GetMtrlPath(item, _material.GetRace(), oldMaterialIdentifier, itemType)).Folder; var match = Regex.Match(variantMtrlPath, "/v([0-9]+)"); var variant = 0; if (match.Success) { variant = Int32.Parse(match.Groups[1].Value); } // Only modify each Variant once. if (modifiedVariants.Contains(variant)) { continue; } var dxVersion = 11; XivMtrl itemXivMtrl; // Get mtrl path -- TODO: Need support here for offhand item materials. // But Offhand support is basically completely broken anyways, so this can wait. itemXivMtrl = await _mtrl.GetMtrlData(_item, _material.GetRace(), oldMaterialIdentifier, dxVersion); // Shift the MTRL to the new variant folder. itemXivMtrl.MTRLPath = Regex.Replace(itemXivMtrl.MTRLPath, oldVariantString, "/v" + variant.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()); } // Write the new Material await _mtrl.ImportMtrl(itemXivMtrl, item, XivStrings.TexTools); modifiedVariants.Add(variant); _view.SaveStatusLabel.Content = "Updated " + modifiedVariants.Count + " Variants..."; } }
/// <summary> /// Gets the list of available mtrl parts for a given item /// </summary> /// <param name="itemModel">An item that contains model data</param> /// <param name="xivRace">The race for the requested data</param> /// <returns>A list of part characters</returns> public async Task <List <string> > GetTexturePartList(IItemModel itemModel, XivRace xivRace, XivDataFile dataFile) { var itemType = ItemType.GetPrimaryItemType(itemModel); var version = "0001"; var id = itemModel.ModelInfo.PrimaryID.ToString().PadLeft(4, '0'); var bodyVer = itemModel.ModelInfo.SecondaryID.ToString().PadLeft(4, '0'); var itemCategory = itemModel.SecondaryCategory; if (itemType != XivItemType.human && itemType != XivItemType.furniture) { // Get the mtrl version for the given item from the imc file var imc = new Imc(_gameDirectory); version = (await imc.GetImcInfo(itemModel)).MaterialSet.ToString().PadLeft(4, '0'); } var parts = Constants.Alphabet; var race = xivRace.GetRaceCode(); string mtrlFolder = "", mtrlFile = ""; switch (itemType) { case XivItemType.equipment: mtrlFolder = $"chara/{itemType}/e{id}/material/v{version}"; mtrlFile = $"mt_c{race}e{id}_{itemModel.GetItemSlotAbbreviation()}_"; break; case XivItemType.accessory: mtrlFolder = $"chara/{itemType}/a{id}/material/v{version}"; mtrlFile = $"mt_c{race}a{id}_{SlotAbbreviationDictionary[itemCategory]}_"; break; case XivItemType.weapon: mtrlFolder = $"chara/{itemType}/w{id}/obj/body/b{bodyVer}/material/v{version}"; mtrlFile = $"mt_w{id}b{bodyVer}_"; break; case XivItemType.monster: mtrlFolder = $"chara/{itemType}/m{id}/obj/body/b{bodyVer}/material/v{version}"; mtrlFile = $"mt_m{id}b{bodyVer}_"; break; case XivItemType.demihuman: mtrlFolder = $"chara/{itemType}/d{id}/obj/body/e{bodyVer}/material/v{version}"; mtrlFile = $"mt_d{id}e{bodyVer}_"; break; case XivItemType.human: if (itemCategory.Equals(XivStrings.Body)) { mtrlFolder = $"chara/{itemType}/c{id}/obj/body/b{bodyVer}/material/v{version}"; mtrlFile = $"mt_c{id}b{bodyVer}_"; } else if (itemCategory.Equals(XivStrings.Hair)) { mtrlFolder = $"chara/{itemType}/c{id}/obj/body/h{bodyVer}/material/v{version}"; mtrlFile = $"mt_c{id}h{bodyVer}_{SlotAbbreviationDictionary[itemCategory]}_"; } else if (itemCategory.Equals(XivStrings.Face)) { mtrlFolder = $"chara/{itemType}/c{id}/obj/body/f{bodyVer}/material/v{version}"; mtrlFile = $"mt_c{id}f{bodyVer}_{SlotAbbreviationDictionary[itemCategory]}_"; } else if (itemCategory.Equals(XivStrings.Tail)) { mtrlFolder = $"chara/{itemType}/c{id}/obj/body/t{bodyVer}/material/v{version}"; mtrlFile = $"mt_c{id}t{bodyVer}_"; } break; case XivItemType.furniture: if (itemCategory.Equals(XivStrings.Furniture_Indoor)) { mtrlFolder = $"bgcommon/hou/indoor/general/{id}/material"; mtrlFile = $"fun_b0_m{id}_0"; } else if (itemCategory.Equals(XivStrings.Furniture_Outdoor)) { mtrlFolder = $"bgcommon/hou/outdoor/general/{id}/material"; mtrlFile = $"gar_b0_m{id}_0"; } break; default: mtrlFolder = ""; break; } // Get a list of hashed mtrl files that are in the given folder var files = await _index.GetAllHashedFilesInFolder(HashGenerator.GetHash(mtrlFolder), dataFile); // append the part char to the mtrl file and see if its hashed value is within the files list var partList = (from part in parts let mtrlCheck = mtrlFile + part + ".mtrl" where files.Contains(HashGenerator.GetHash(mtrlCheck)) select part.ToString()).ToList(); if (partList.Count < 1 && itemType == XivItemType.furniture) { if (itemCategory.Equals(XivStrings.Furniture_Indoor)) { mtrlFile = $"fun_b0_m{id}_1"; } else if (itemCategory.Equals(XivStrings.Furniture_Outdoor)) { mtrlFile = $"gar_b0_m{id}_1"; } // Get a list of hashed mtrl files that are in the given folder files = await _index.GetAllHashedFilesInFolder(HashGenerator.GetHash(mtrlFolder), dataFile); // append the part char to the mtrl file and see if its hashed value is within the files list partList = (from part in parts let mtrlCheck = mtrlFile + part + ".mtrl" where files.Contains(HashGenerator.GetHash(mtrlCheck)) select part.ToString()).ToList(); } // returns the list of parts that exist within the mtrl folder return(partList); }
/// <summary> /// Gets the available races that contain texture data for the given gear /// </summary> /// <remarks> /// This checks to see if the mtrl file for each race exists in the mtrl folder /// It creates a list of the races which do have an available mtrl folder /// </remarks> /// <param name="xivGear">A gear item</param> /// <returns>A list of XivRace data</returns> public async Task <List <XivRace> > GetRacesForTextures(XivGear xivGear, XivDataFile dataFile) { // Get the material version for the item from the imc file var imc = new Imc(_gameDirectory); var gearVersion = (await imc.GetImcInfo(xivGear)).Variant.ToString().PadLeft(4, '0'); var modelID = xivGear.ModelInfo.PrimaryID.ToString().PadLeft(4, '0'); var raceList = new List <XivRace>(); var itemType = ItemType.GetPrimaryItemType(xivGear); string mtrlFolder; if (itemType == XivItemType.weapon) { return(new List <XivRace> { XivRace.All_Races }); } switch (itemType) { case XivItemType.equipment: mtrlFolder = $"chara/{itemType}/e{modelID}/material/v{gearVersion}"; break; case XivItemType.accessory: mtrlFolder = $"chara/{itemType}/a{modelID}/material/v{gearVersion}"; break; default: mtrlFolder = ""; break; } var testFilesDictionary = new Dictionary <int, string>(); // loop through each race ID to create a dictionary containing [Hashed file name, race ID] foreach (var ID in IDRaceDictionary.Keys) { string mtrlFile; switch (itemType) { case XivItemType.equipment: mtrlFile = $"mt_c{ID}e{modelID}_{xivGear.GetItemSlotAbbreviation()}_a.mtrl"; break; case XivItemType.accessory: mtrlFile = $"mt_c{ID}a{modelID}_{xivGear.GetItemSlotAbbreviation()}_a.mtrl"; break; default: mtrlFile = ""; break; } testFilesDictionary.Add(HashGenerator.GetHash(mtrlFile), ID); } // get the list of hashed file names from the mtrl folder var files = await _index.GetAllHashedFilesInFolder(HashGenerator.GetHash(mtrlFolder), dataFile); // Loop through each entry in the dictionary foreach (var testFile in testFilesDictionary) { // if the file in the dictionary entry is contained in the list of files from the folder // add that race to the race list if (files.Contains(testFile.Key)) { raceList.Add(IDRaceDictionary[testFile.Value]); } } return(raceList); }