public async Task ShowConversionStats() { if (!DestinationOk(Destination)) { return; } var imc = new Imc(XivCache.GameInfo.GameDirectory); SourceBox.Text = Source.Info.GetBaseFileName() + " (" + SourceItem.Name + ")"; DestinationBox.Text = Destination.Info.GetBaseFileName() + " (" + DestinationItem.Name + ")"; if (Imc.UsesImc(Source)) { try { var sourceInfo = await imc.GetFullImcInfo(Source.GetRawImcFilePath()); var destInfo = await imc.GetFullImcInfo(Destination.GetRawImcFilePath()); SourceVariantsBox.Text = (sourceInfo.SubsetCount + 1).ToString(); DestinationVariantsBox.Text = (destInfo.SubsetCount + 1).ToString(); SameVariantBox.IsEnabled = true; SameVariantBox.IsChecked = true; } catch { SameVariantBox.IsEnabled = true; SameVariantBox.IsChecked = true; } } else { SameVariantBox.IsEnabled = false; SameVariantBox.IsChecked = false; SourceVariantsBox.Text = "1"; DestinationVariantsBox.Text = "1"; } var items = await Destination.GetAllItems(); AffectedItemsBox.Items.Clear(); foreach (var item in items) { AffectedItemsBox.Items.Add(item.Name); } }
/// <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); }
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 HashSet <string>(); var root = _item.GetRoot(); if (root == null || !Imc.UsesImc(root)) { // This is the only copy of the material we know how to find. files.Add(_material.MTRLPath); } else { var imc = new Imc(XivCache.GameInfo.GameDirectory); var info = await imc.GetFullImcInfo(_item); var entries = info.GetAllEntries(root.Info.Slot); var materialSets = entries.Select(x => x.MaterialSet).ToHashSet(); var extract = new Regex("(v[0-9]{4})"); var rep = extract.Match(_material.MTRLPath).Groups[1].Value; // Remove the material in all of the referenced material sets. foreach (var setId in materialSets) { var newPath = _material.MTRLPath.Replace(rep, "v" + setId.ToString().PadLeft(4, '0')); files.Add(newPath); } } try { foreach (var file in files) { var modEntry = await _modding.TryGetModEntry(file); if (modEntry == null) { continue; } // If the file is a custom addition, and not a modification. if (modEntry.IsCustomFile()) { await _modding.DeleteMod(file); } else { await _modding.ToggleModStatus(file, false); } } } catch (Exception ex) { FlexibleMessageBox.Show("Unable to delete Mod.\n\nError: " + ex.Message, "Mod Delete Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } _view.Close(false); }
public async Task SaveMulti() { var _imc = new Imc(XivCache.GameInfo.GameDirectory); var _index = new Index(XivCache.GameInfo.GameDirectory); // 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(); var oldMtrlName = Path.GetFileName(_material.MTRLPath); // 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"; if (_mode == MaterialEditorMode.NewRace) { mtrlReplacementRegexResult = mtrlReplacementRegex; } var newMtrlName = oldMtrlName.Replace(mtrlReplacementRegex, mtrlReplacementRegexResult); var root = _item.GetRootInfo(); var imcEntries = new List <XivImc>(); var materialSets = new HashSet <byte>(); try { var imcInfo = await _imc.GetFullImcInfo(_item); imcEntries = imcInfo.GetAllEntries(root.Slot, true); materialSets = imcEntries.Select(x => x.MaterialSet).ToHashSet(); } catch { // Item doesn't use IMC entries, and thus only has a single variant. materialSets.Clear(); materialSets.Add(0); } // We need to save our non-existent base material once before we can continue. if (_mode == MaterialEditorMode.NewRace) { await _mtrl.ImportMtrl(_material, _item, XivStrings.TexTools); } var count = 0; var allItems = (await root.ToFullRoot().GetAllItems()); var matNumToItems = new Dictionary <int, List <IItemModel> >(); foreach (var i in allItems) { if (imcEntries.Count <= i.ModelInfo.ImcSubsetID) { continue; } var matSet = imcEntries[i.ModelInfo.ImcSubsetID].MaterialSet; if (!matNumToItems.ContainsKey(matSet)) { matNumToItems.Add(matSet, new List <IItemModel>()); } var saveItem = i; if (typeof(XivCharacter) == i.GetType()) { var temp = (XivCharacter)((XivCharacter)_item).Clone(); temp.Name = saveItem.SecondaryCategory; saveItem = temp; } matNumToItems[matSet].Add(saveItem); } var keys = matNumToItems.Keys.ToList(); foreach (var key in keys) { var list = matNumToItems[key]; matNumToItems[key] = list.OrderBy(x => x.Name, new ItemNameComparer()).ToList(); } // Load and modify all the MTRLs. foreach (var materialSetId in materialSets) { var variantPath = _mtrl.GetMtrlFolder(root, materialSetId); var oldMaterialPath = variantPath + "/" + oldMtrlName; var newMaterialPath = variantPath + "/" + newMtrlName; // Don't create materials for set 0. (SE sets the material ID to 0 when that particular set-slot doesn't actually exist as an item) if (materialSetId == 0 && imcEntries.Count > 0) { continue; } var dxVersion = 11; XivMtrl itemXivMtrl; // Get mtrl path if (await _index.FileExists(oldMaterialPath)) { // Use the Material from this variant as a base? itemXivMtrl = await _mtrl.GetMtrlData(_item, oldMaterialPath, dxVersion); } else { itemXivMtrl = await _mtrl.GetMtrlData(_item, _material.MTRLPath, dxVersion); } // If we're an item that doesn't use IMC variants, make sure we don't accidentally move the material around. if (materialSetId != 0) { // Shift the MTRL to the new variant folder. itemXivMtrl.MTRLPath = Regex.Replace(itemXivMtrl.MTRLPath, oldVariantString, "/v" + materialSetId.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()); } IItem item; try { item = matNumToItems[materialSetId].First(); } catch { item = (await XivCache.GetFirstRoot(itemXivMtrl.MTRLPath)).GetFirstItem(); } count++; // Write the new Material await _mtrl.ImportMtrl(itemXivMtrl, item, XivStrings.TexTools); _view.SaveStatusLabel.Content = "Updated " + count + "/" + materialSets.Count + " Material Sets..."; } }
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 async Task SetFile(string filePath) { await LockUi(); WarningLabel.Text = ""; _path = filePath; ChildFilesBox.Items.Clear(); ParentFilesBox.Items.Clear(); SiblingFilesBox.Items.Clear(); AffectedItemsBox.Items.Clear(); ModelLevelBox.Text = ""; MaterialLevelBox.Text = ""; FilePathLabel.Text = filePath; FileNameBox.Text = Path.GetFileName(filePath); var root = await XivCache.GetFirstRoot(filePath); if (root == null) { RootNameBox.Text = "NULL"; WarningLabel.Text = "File dependency information not supported for this item."; await UnlockUi(); return; } RootNameBox.Text = root.ToRawItem().Name; var ext = Path.GetExtension(filePath).Substring(1); var allItems = (await root.GetAllItems()); if (allItems.Count == 0) { WarningLabel.Text = "File dependency information not supported for this item."; await UnlockUi(); return; } if (root.Info.PrimaryType == XivItemType.human) { WarningLabel.Text = "Parent file references & affected items lists \n may not be complete for this file. \n (Unknown cross-references may exist.)"; } var orderedItems = allItems.OrderBy((x => x.Name), new ItemNameComparer()).ToList(); var modelItem = orderedItems[0]; ModelLevelBox.Text = modelItem.Name; var children = await XivCache.GetChildFiles(filePath); var parents = await XivCache.GetParentFiles(filePath); var siblings = await XivCache.GetSiblingFiles(filePath); foreach (var s in children) { ChildFilesBox.Items.Add(s); } foreach (var s in parents) { ParentFilesBox.Items.Add(s); } foreach (var s in siblings) { SiblingFilesBox.Items.Add(s); } Dictionary <XivDependencyRoot, HashSet <int> > mVariants = new Dictionary <XivDependencyRoot, HashSet <int> >(); var affectedItems = new List <IItem>(); if (ext == "tex") { foreach (var parent in parents) { // Each of our parents has a root... var pRoot = await XivCache.GetFirstRoot(parent); if (pRoot == null) { continue; } // And each of these files also has a material set id. var match = _extractVariant.Match(parent); var mVariant = 0; if (match.Success) { mVariant = Int32.Parse(match.Groups[1].Value); } if (!mVariants.ContainsKey(pRoot)) { mVariants.Add(pRoot, new HashSet <int>()); } mVariants[pRoot].Add(mVariant); var pItems = (await pRoot.GetAllItems()); } } else if (ext == "mtrl") { var match = _extractVariant.Match(filePath); var mVariant = 0; if (match.Success) { mVariant = Int32.Parse(match.Groups[1].Value); } if (!mVariants.ContainsKey(root)) { mVariants.Add(root, new HashSet <int>()); } mVariants[root].Add(mVariant); } else { foreach (var item in allItems) { affectedItems.Add(item); } MaterialLevelBox.Text = ""; } Dictionary <XivDependencyRoot, HashSet <int> > sharedImcSubsets = new Dictionary <XivDependencyRoot, HashSet <int> >(); var _imc = new Imc(XivCache.GameInfo.GameDirectory); try { // We now have a dictionary of <Root>, <Material Set Id> that comprises all of our referencing material sets. // We now need to convert that into a list of <root> => <Imc Subset IDs>, for all IMC subsets in that root which use our material ID. foreach (var kv in mVariants) { var rt = kv.Key; sharedImcSubsets.Add(rt, new HashSet <int>()); var imcPath = rt.GetRawImcFilePath(); var fullImcInfo = await _imc.GetFullImcInfo(imcPath); var setCount = fullImcInfo.SubsetCount + 1; for (int i = 0; i < setCount; i++) { var info = fullImcInfo.GetEntry(i, rt.Info.Slot); // This IMC subset references the one of our material sets. if (kv.Value.Contains(info.Variant)) { sharedImcSubsets[rt].Add(i); } } } // We now have a dictionary of <root>, <imc subset ids>. At this point, we can compare this to our original alll items list. var sh = allItems.Where(x => { var iRoot = x.GetRoot(); // The root must be one of our roots we care about. if (!sharedImcSubsets.ContainsKey(iRoot)) { return(false); } var imcs = sharedImcSubsets[iRoot]; // The imc subset must be in the imc subsets that use this material. if (!imcs.Contains(x.ModelInfo.ImcSubsetID)) { return(false); } return(true); }); foreach (var i in sh) { affectedItems.Add(i); } } catch { // The item doesn't have a valid IMC entry. In that case, it affects all items in the tree. affectedItems.AddRange(allItems); } if (affectedItems.Count == 0) { MaterialLevelBox.Text = "Unknown"; } else { if (ext == "tex" || ext == "mtrl") { var ordered = affectedItems.OrderBy((x => x.Name), new ItemNameComparer()).ToList(); MaterialLevelBox.Text = ordered[0].Name; } } foreach (var item in affectedItems) { AffectedItemsBox.Items.Add(item); } await UnlockUi(); }