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);
        }
Ejemplo n.º 3
0
        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);
        }
Ejemplo n.º 4
0
        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...";
            }
        }
Ejemplo n.º 5
0
        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));
                    }
                }
            }
        }
Ejemplo n.º 6
0
        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();
        }