예제 #1
0
        public void LoadSelectedCollection(string collectionName)
        {
            var thisUWC = WardrobeCollectionLibrary.Instance.collectionIndex[collectionName];

            if (thisUWC != null)
            {
                thisUWC.EnsureLocalAvailability();
            }
            if (thisCustomizer.Avatar != null)
            {
                //is this UWC compatible with the current race of the avatar?
                //even if its not it should be made available to races that are?
                if (!thisUWC.compatibleRaces.Contains(thisCustomizer.Avatar.activeRace.name) && thisUWC.compatibleRaces.Count > 0)
                {
                    //show a messagebox- but for now
                    Debug.LogWarning("This wardrobe collection was not compatible with that avatar");
                    return;
                }
                //if not show a message otherwise load the recipe
                var thisContext = thisCustomizer.Avatar.context != null ? thisCustomizer.Avatar.context : UMAContext.FindInstance();
                if (thisContext != null)
                {
                    var thisDCS = (thisContext.dynamicCharacterSystem as DynamicCharacterSystem);
                    if (thisDCS != null)
                    {
                        thisDCS.GetRecipe(collectionName, true);
                        //if there is actually a 'FullOutfit' defined for the current avatar(i.e. the WardrobeSet for this race is not empty) load it
                        if (thisUWC.wardrobeCollection[thisCustomizer.Avatar.activeRace.name].Count > 0)
                        {
                            thisCustomizer.Avatar.SetSlot(thisUWC);
                            thisCustomizer.Avatar.BuildCharacter();
                        }
                    }
                }
                onLoadCollection.Invoke();
                //if this was not a recipe that will actually load a FullOutfit onto this race, show a message saying the assets have been added to the library
                if (thisUWC.wardrobeCollection[thisCustomizer.Avatar.activeRace.name].Count == 0 && thisUWC.arbitraryRecipes.Count > 0)
                {
                    dialogBoxes.SetActive(true);
                    messageBox.SetActive(true);
                    messageHeader.text = thisUWC.name + " Loaded!";
                    messageBody.text   = "The wardrobe recipes in " + thisUWC.name + " have been added to the DCS libraries. Compatible recipes can now be applied to your character using the 'Wardrobe' section of the UI.";
                }
            }
        }
예제 #2
0
            public bool OnGUI()
            {
                if (warningIcon == null)
                {
                    warningIcon = EditorGUIUtility.FindTexture("console.warnicon.sml");
                }
                bool changed = false;
                var  context = UMAContext.FindInstance();

                if (context == null)
                {
                    var _errorMessage = "Editing a recipe requires a loaded scene with a valid UMAContext.";
                    Debug.LogWarning(_errorMessage);
                }
                var           recipesForRaceSlot = context.dynamicCharacterSystem.GetRecipeNamesForRaceSlot(_wsRace, _wsSlot);
                List <string> thisPopupVals      = new List <string>();

                thisPopupVals.Add("None");
                thisPopupVals.AddRange(recipesForRaceSlot);
                var  selected     = 0;
                var  recipeIsLive = true;
                Rect valRBut      = new Rect();
                var  warningStyle = new GUIStyle(EditorStyles.label);

                warningStyle.fixedHeight   = warningIcon.height + 4f;
                warningStyle.contentOffset = new Vector2(0, -2f);
                if (_wsRecipeName != "")
                {
                    recipeIsLive = context.dynamicCharacterSystem.CheckRecipeAvailability(_wsRecipeName);
                    selected     = thisPopupVals.IndexOf(_wsRecipeName);
                    if (selected == -1)
                    {
                        selected = thisPopupVals.Count;
                        string missingOrIncompatible = "missing";
                        if (context.dynamicCharacterSystem.GetBaseRecipe(_wsRecipeName, false) != null)
                        {
                            missingOrIncompatible = "incompatible";
                        }
                        thisPopupVals.Add(_wsRecipeName + " (" + missingOrIncompatible + ")");
                    }
                }
                var newSelected = selected;

                if (!recipeIsLive)
                {
                    EditorGUI.indentLevel++;
                }
                var label = _wsSlot == "WardrobeCollection" ? " " : _wsSlot;

                EditorGUI.BeginChangeCheck();
                newSelected = EditorGUILayout.Popup(label, selected, thisPopupVals.ToArray());
                if (!recipeIsLive)
                {
                    EditorGUI.indentLevel--;
                    valRBut = GUILayoutUtility.GetLastRect();
                }
                if (EditorGUI.EndChangeCheck())
                {
                    if (newSelected != selected)
                    {
                        changed       = true;
                        _wsRecipeName = (thisPopupVals[newSelected].IndexOf("(missing)") == -1 && thisPopupVals[newSelected].IndexOf("(incompatible)") == -1) ? (thisPopupVals[newSelected] != "None" ? thisPopupVals[newSelected] : "") : _wsRecipeName.Replace("(missing)", "").Replace("(incompatible)", "");
                    }
                }
                if (!recipeIsLive)
                {
                    var warningRect       = new Rect((valRBut.xMin - 5f), valRBut.yMin, 20f, valRBut.height);
                    var warningGUIContent = new GUIContent("", _wsRecipeName + " was not Live. You can make it live by adding it to the UMA/UMA Global Library.");
                    warningGUIContent.image = warningIcon;
                    GUI.Button(warningRect, warningGUIContent, warningStyle);
                    //TODO we can probably use AssetIndexer.AddEvilAsset here so it gets added without having to go there
                    //Id like this to be a button that opens the window, opens the recipe section and ideally highlights the asset that needs to be made live

                    /*if(GUI.Button(warningRect, warningGUIContent, warningStyle))
                     * {
                     *      UMAAssetIndexWindow.Init();
                     * }*/
                }
                return(changed);
            }
예제 #3
0
            private void UpdateBackwardsCompatibleData()
            {
                var context = UMAContext.FindInstance();

                if (context == null)
                {
                    var _errorMessage = "Editing a recipe requires a loaded scene with a valid UMAContext.";
                    Debug.LogWarning(_errorMessage);
                }
                //reset the recipe to the raceBase recipe
                var thisBaseRecipe = _recipe.raceData.baseRaceRecipe;

                thisBaseRecipe.Load(_recipe, context);
                if (_wardrobeSet.Count > 0)
                {
                    var thisDCS = context.dynamicCharacterSystem;
                    if (thisDCS == null)
                    {
                        var _errorMessage = "Editing a recipe requires a loaded scene with a valid UMAContext.";
                        Debug.LogWarning(_errorMessage);
                    }
                    List <UMARecipeBase> Recipes = new List <UMARecipeBase>();
                    List <string>        SuppressSlotsStrings = new List <string>();
                    List <string>        HiddenSlots          = new List <string>();
                    var wardrobeRecipesToRender = new Dictionary <string, UMARecipeBase>();
                    var activeRace = _recipe.raceData.raceName;
                    //Dont add the WardrobeCollection to the recipes to render- they doesn't render directly and will have already set their actual wardrobeRecipe slots SetSlot
                    foreach (WardrobeSettings set in _wardrobeSet)
                    {
                        var thisRecipe = thisDCS.GetBaseRecipe(set.recipe);
                        if (thisRecipe == null)
                        {
                            continue;
                        }
                        if (thisRecipe.GetType().ToString() == "UMAWardrobeCollection")
                        {
                            var       TargetType = thisRecipe.GetType();
                            FieldInfo WardrobeCollectionField         = TargetType.GetField("wardrobeCollection", BindingFlags.Public | BindingFlags.Instance);
                            WardrobeCollectionList wardrobeCollection = (WardrobeCollectionList)WardrobeCollectionField.GetValue(thisRecipe);
                            if (wardrobeCollection[activeRace] != null)
                            {
                                foreach (WardrobeSettings ws in wardrobeCollection[activeRace])
                                {
                                    var wsRecipe = thisDCS.GetBaseRecipe(ws.recipe);
                                    if (wsRecipe != null)
                                    {
                                        if (wardrobeRecipesToRender.ContainsKey(ws.slot))
                                        {
                                            wardrobeRecipesToRender[ws.slot] = wsRecipe;
                                        }
                                        else
                                        {
                                            wardrobeRecipesToRender.Add(ws.slot, wsRecipe);
                                        }
                                    }
                                }
                            }
                        }
                        else
                        {
                            //_recipe.Merge(thisRecipe.GetCachedRecipe(context), true);
                            if (wardrobeRecipesToRender.ContainsKey(set.slot))
                            {
                                wardrobeRecipesToRender[set.slot] = thisRecipe;
                            }
                            else
                            {
                                wardrobeRecipesToRender.Add(set.slot, thisRecipe);
                            }
                        }
                    }
                    if (wardrobeRecipesToRender.Count > 0)
                    {
                        foreach (UMARecipeBase utr in wardrobeRecipesToRender.Values)
                        {
                            var       TargetType                = utr.GetType();
                            FieldInfo CompatibleRacesField      = TargetType.GetField("compatibleRaces", BindingFlags.Public | BindingFlags.Instance);
                            FieldInfo WardrobeSlotField         = TargetType.GetField("wardrobeSlot", BindingFlags.Public | BindingFlags.Instance);
                            FieldInfo SuppressWardrobeSlotField = TargetType.GetField("suppressWardrobeSlots", BindingFlags.Public | BindingFlags.Instance);

                            //field values
                            List <string> compatibleRaces      = (List <string>)CompatibleRacesField.GetValue(utr);
                            string        wardrobeSlot         = (string)WardrobeSlotField.GetValue(utr);
                            List <string> suppressWardrobeSlot = (List <string>)SuppressWardrobeSlotField.GetValue(utr);

                            if (suppressWardrobeSlot != null)
                            {
                                if (activeRace == "" || ((compatibleRaces.Count == 0 || compatibleRaces.Contains(activeRace)) || (_recipe.raceData.findBackwardsCompatibleWith(compatibleRaces) && _recipe.raceData.wardrobeSlots.Contains(wardrobeSlot))))
                                {
                                    if (!SuppressSlotsStrings.Contains(wardrobeSlot))
                                    {
                                        foreach (string suppressedSlot in suppressWardrobeSlot)
                                        {
                                            SuppressSlotsStrings.Add(suppressedSlot);
                                        }
                                    }
                                }
                            }
                        }
                    }
                    foreach (string ws in _recipe.raceData.wardrobeSlots)
                    {
                        if (SuppressSlotsStrings.Contains(ws))
                        {
                            continue;
                        }
                        if (wardrobeRecipesToRender.ContainsKey(ws))
                        {
                            UMARecipeBase utr                  = wardrobeRecipesToRender[ws];
                            var           TargetType           = wardrobeRecipesToRender[ws].GetType();
                            FieldInfo     CompatibleRacesField = TargetType.GetField("compatibleRaces", BindingFlags.Public | BindingFlags.Instance);
                            FieldInfo     WardrobeSlotField    = TargetType.GetField("wardrobeSlot", BindingFlags.Public | BindingFlags.Instance);
                            FieldInfo     HidesField           = TargetType.GetField("Hides", BindingFlags.Public | BindingFlags.Instance);

                            //field values
                            List <string> compatibleRaces = (List <string>)CompatibleRacesField.GetValue(utr);
                            string        wardrobeSlot    = (string)WardrobeSlotField.GetValue(utr);
                            List <string> hides           = (List <string>)HidesField.GetValue(utr);

                            if (activeRace == "" || ((compatibleRaces.Count == 0 || compatibleRaces.Contains(activeRace)) || (_recipe.raceData.findBackwardsCompatibleWith(compatibleRaces) && _recipe.raceData.wardrobeSlots.Contains(wardrobeSlot))))
                            {
                                Recipes.Add(utr);
                                if (hides.Count > 0)
                                {
                                    foreach (string s in hides)
                                    {
                                        HiddenSlots.Add(s);
                                    }
                                }
                            }
                        }
                    }
                    //merge them in
                    foreach (var additionalRecipe in Recipes)
                    {
                        _recipe.Merge(additionalRecipe.GetCachedRecipe(context), true);
                    }
                    if (HiddenSlots.Count > 0)
                    {
                        List <SlotData> NewSlots = new List <SlotData>();
                        foreach (SlotData sd in _recipe.slotDataList)
                        {
                            if (sd == null)
                            {
                                continue;
                            }
                            if (!HiddenSlots.Contains(sd.asset.slotName))
                            {
                                NewSlots.Add(sd);
                            }
                        }
                        _recipe.slotDataList = NewSlots.ToArray();
                    }
                    ResetSlotEditors();
                }
            }
예제 #4
0
            public override bool OnGUI(string targetName, ref bool _dnaDirty, ref bool _textureDirty, ref bool _meshDirty)
            {
                bool changed = false;

                if (_sharedColorsEditor.OnGUI(_recipe))
                {
                    changed       = true;
                    _textureDirty = true;
                }

                GUILayout.Space(6);
                Rect dropArea = GUILayoutUtility.GetRect(0.0f, 50.0f, GUILayout.ExpandWidth(true));

                GUI.Box(dropArea, "Drag Slots and Overlays here. Click to pick");
                if (DropAreaGUI(dropArea))
                {
                    changed       |= true;
                    _dnaDirty     |= true;
                    _textureDirty |= true;
                    _meshDirty    |= true;
                }
                GUILayout.Space(10);

                if (_baseSlotOptions.Count > 0)
                {
                    var baseSlotsNamesList = new List <string>()
                    {
                        "None"
                    };
                    for (int i = 0; i < _baseSlotOptionsLabels.Count; i++)
                    {
                        baseSlotsNamesList.Add(_baseSlotOptionsLabels[i]);
                    }
                    EditorGUI.BeginChangeCheck();
                    var baseAdded = EditorGUILayout.Popup("Add Base Slot", 0, baseSlotsNamesList.ToArray());
                    if (EditorGUI.EndChangeCheck())
                    {
                        if (baseAdded != 0)
                        {
                            var slotName = _baseSlotOptions[baseAdded - 1];
                            LastSlot = slotName;
                            //we know there should be one because we created a virtual one when we unpacked the recipe if it didn't exist
                            var context   = UMAContext.FindInstance();
                            var slotToAdd = context.InstantiateSlot(slotName);
                            _recipe.MergeSlot(slotToAdd, false);
                            changed       |= true;
                            _dnaDirty     |= true;
                            _textureDirty |= true;
                            _meshDirty    |= true;
                        }
                    }
                }

                var added = (SlotDataAsset)EditorGUILayout.ObjectField("Add Slot", null, typeof(SlotDataAsset), false);

                if (added != null)
                {
                    LastSlot = added.slotName;
                    var slot = new SlotData(added);
                    _recipe.MergeSlot(slot, false);
                    changed       |= true;
                    _dnaDirty     |= true;
                    _textureDirty |= true;
                    _meshDirty    |= true;
                }

                GUILayout.Space(20);
                GUILayout.BeginHorizontal();
                if (GUILayout.Button("Clear Recipe"))
                {
                    _recipe.slotDataList = new SlotData[0];
                    changed       |= true;
                    _dnaDirty     |= true;
                    _textureDirty |= true;
                    _meshDirty    |= true;
                }
                if (GUILayout.Button("Remove Nulls"))
                {
                    var newList = new List <SlotData>(_recipe.slotDataList.Length);
                    foreach (var slotData in _recipe.slotDataList)
                    {
                        if (slotData != null)
                        {
                            newList.Add(slotData);
                        }
                    }
                    _recipe.slotDataList = newList.ToArray();
                    changed       |= true;
                    _dnaDirty     |= true;
                    _textureDirty |= true;
                    _meshDirty    |= true;
                }
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                if (GUILayout.Button("Collapse All"))
                {
                    foreach (SlotEditor se in _slotEditors)
                    {
                        se.FoldOut = false;
                    }
                }
                if (GUILayout.Button("Expand All"))
                {
                    foreach (SlotEditor se in _slotEditors)
                    {
                        se.FoldOut = true;
                    }
                }
                GUILayout.EndHorizontal();
                GUILayout.BeginHorizontal();

                if (GUILayout.Button("Select All Slots"))
                {
                    SelectAllSlots();
                }
                if (GUILayout.Button("Select All Overlays"))
                {
                    SelectAllOverlays();
                }

                GUILayout.EndHorizontal();

                for (int i = 0; i < _slotEditors.Count; i++)
                {
                    var editor = _slotEditors[i];

                    if (editor == null)
                    {
                        GUILayout.Label("Empty Slot");
                        continue;
                    }

                    changed |= editor.OnGUI(ref _dnaDirty, ref _textureDirty, ref _meshDirty);

                    if (editor.Delete)
                    {
                        _dnaDirty     = true;
                        _textureDirty = true;
                        _meshDirty    = true;

                        _slotEditors.RemoveAt(i);
                        _recipe.SetSlot(editor.idx, null);
                        i--;
                        changed = true;
                    }
                }

                return(changed);
            }
예제 #5
0
            public bool OnGUI()
            {
                bool changed = false;

                if (_race != null)
                {
                    if (_race.wardrobeSlots.Count > 0)
                    {
                        var context = UMAContext.FindInstance();
                        if (context == null)
                        {
                            var _errorMessage = "Editing a recipe requires a loaded scene with a valid UMAContext.";
                            Debug.LogWarning(_errorMessage);
                        }

                        if (_wardrobeSet == null || context == null)
                        {
                            return(false);
                        }
                        GUIHelper.BeginVerticalPadded(10, new Color(0.75f, 0.875f, 1f));
                        if (_allowWardrobeCollectionSlot)
                        {
                            var wcRecipesForRace = context.dynamicCharacterSystem.GetRecipesForRaceSlot(_race.raceName, "WardrobeCollection");
                            var wcGroupDict      = new Dictionary <string, List <string> >();
                            //for 'Standard Assets' we need to do some kind of get Types thing I think because we then need to use reflection to get the wardrobeSlot field
                            //how can we get what we want here when WardrobeCollections dont exist in Standard Assets (if 'StandardAssets' has been moved there)
                            for (int i = 0; i < wcRecipesForRace.Count; i++)
                            {
                                Type wcType = wcRecipesForRace[i].GetType();
                                if (wcType.ToString() == "UMAWardrobeCollection")
                                {
                                    FieldInfo wcRecipeSlotField = wcType.GetField("wardrobeSlot", BindingFlags.Public | BindingFlags.Instance);
                                    var       wcRecipeSlot      = (string)wcRecipeSlotField.GetValue(wcRecipesForRace[i]);
                                    if (!wcGroupDict.ContainsKey(wcRecipeSlot))
                                    {
                                        wcGroupDict.Add(wcRecipeSlot, new List <string>());
                                    }
                                    wcGroupDict[wcRecipeSlot].Add(wcRecipesForRace[i].name);
                                }
                            }
                            if (wcGroupDict.Count > 0)
                            {
                                EditorGUILayout.LabelField("WardrobeCollections");
                                EditorGUI.indentLevel++;
                                foreach (KeyValuePair <string, List <string> > kp in wcGroupDict)
                                {
                                    var thisPopupVals = new List <string>();
                                    thisPopupVals.Add("None");
                                    thisPopupVals.AddRange(kp.Value);
                                    var selected   = 0;
                                    var prevRecipe = "";
                                    //if one of the recipes in the wardrobe set is one of these then its selected
                                    for (int pvi = 0; pvi < thisPopupVals.Count; pvi++)
                                    {
                                        for (int wsi = 0; wsi < _wardrobeSet.Count; wsi++)
                                        {
                                            if (thisPopupVals[pvi] == _wardrobeSet[wsi].recipe)
                                            {
                                                prevRecipe = _wardrobeSet[wsi].recipe;
                                                selected   = pvi;
                                                break;
                                            }
                                        }
                                    }
                                    EditorGUI.BeginChangeCheck();
                                    var newSelected = EditorGUILayout.Popup(kp.Key, selected, thisPopupVals.ToArray());
                                    if (EditorGUI.EndChangeCheck())
                                    {
                                        for (int wsi = 0; wsi < _wardrobeSet.Count; wsi++)
                                        {
                                            if (_wardrobeSet[wsi].recipe == prevRecipe)
                                            {
                                                //we need to remove the wardrobeSettings that has prevRecipe as its value from _wardrobeSettings
                                                if (newSelected == 0)
                                                {
                                                    _wardrobeSet.RemoveAt(wsi);
                                                }
                                                else
                                                {
                                                    //we need to make wardrobeSettings that has prevRecipe have the new value
                                                    _wardrobeSet[wsi].recipe = thisPopupVals[newSelected];
                                                }
                                            }
                                        }
                                        changed = true;
                                    }
                                }
                                EditorGUI.indentLevel--;
                                EditorGUILayout.Space();
                                EditorGUILayout.LabelField("WardrobeSlots");
                                EditorGUI.indentLevel++;
                            }
                        }
                        foreach (string wsl in _race.wardrobeSlots)
                        {
                            if (wsl == "None")
                            {
                                continue;
                            }

                            if (wsl == "FullOutfit" && _allowWardrobeCollectionSlot == false)
                            {
                                continue;
                            }

                            WardrobeSlotRecipePopup thisPicker = null;
                            bool assignedPicker = false;
                            for (int wsi = 0; wsi < _wardrobeSet.Count; wsi++)
                            {
                                if (_wardrobeSet[wsi].slot == wsl)
                                {
                                    thisPicker     = new WardrobeSlotRecipePopup(_race.raceName, wsl, _wardrobeSet[wsi].recipe);
                                    assignedPicker = true;
                                    break;
                                }
                            }
                            if (!assignedPicker)                            //means there was nothing in the wardrobe set for it
                            {
                                thisPicker = new WardrobeSlotRecipePopup(_race.raceName, wsl, "");
                            }
                            if (thisPicker.OnGUI())
                            {
                                changed = true;
                                if (thisPicker.RecipeName != "None" && thisPicker.RecipeName != "")
                                {
                                    bool contained = false;
                                    for (int i = 0; i < _wardrobeSet.Count; i++)
                                    {
                                        if (_wardrobeSet[i].slot == wsl)
                                        {
                                            _wardrobeSet[i].recipe = thisPicker.RecipeName;
                                            contained = true;
                                            break;
                                        }
                                    }
                                    if (!contained)
                                    {
                                        _wardrobeSet.Add(new WardrobeSettings(wsl, thisPicker.RecipeName));
                                    }
                                }
                                else
                                {
                                    for (int i = 0; i < _wardrobeSet.Count; i++)
                                    {
                                        if (_wardrobeSet[i].slot == wsl)
                                        {
                                            _wardrobeSet.RemoveAt(i);
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                        if (_allowWardrobeCollectionSlot)
                        {
                            EditorGUI.indentLevel--;
                        }
                        if (WardrobeSet.Count > 0)
                        {
                            EditorGUILayout.Space();
                            if (GUILayout.Button(new GUIContent("UpdateSharedColors", "Automatically adds any shared colors defined in the selected recipes to this recipes SharedColors")))
                            {
                                for (int i = 0; i < _wardrobeSet.Count; i++)
                                {
                                    changed = AddSharedColorsFromRecipe(_wardrobeSet[i].recipe, _recipe) == true ? true : changed;
                                }
                            }
                        }
                        GUIHelper.EndVerticalPadded(10);
                    }
                }
                return(changed);
            }
예제 #6
0
#pragma warning restore 0414

        // Use this for initialization
        void Start()
        {
            avatar = GetComponent <DynamicCharacterAvatar>();
            avatar.CharacterBegun.AddListener(CharacterBegun);
            context = UMAContext.FindInstance();
        }
            public override bool OnGUI(string targetName, ref bool _dnaDirty, ref bool _textureDirty, ref bool _meshDirty)
            {
                var context = UMAContext.FindInstance();

                if (context == null)
                {
                    var _errorMessage = "Editing a recipe requires a loaded scene with a valid UMAContext.";
                    Debug.LogWarning(_errorMessage);
                    return(false);
                }
                bool changed = forceGUIUpdate;

                //Make a foldout for WardrobeSets - the UI for an individual WardrobeSet is added for each compatible race in the collection
                GUILayout.BeginHorizontal(EditorStyles.toolbarButton);
                GUILayout.Space(10);
                bool wsfoldoutOpen = OpenSlots["wardrobeSets"];

                wsfoldoutOpen             = EditorGUILayout.Foldout(OpenSlots["wardrobeSets"], "Wardrobe Sets");
                OpenSlots["wardrobeSets"] = wsfoldoutOpen;
                GUILayout.EndHorizontal();
                if (wsfoldoutOpen)
                {
                    GUIHelper.BeginVerticalPadded(10, new Color(0.75f, 0.875f, 1f));

                    EditorGUILayout.HelpBox("Wardrobe Sets are added for each 'Compatible Race' assigned above. 'SharedColors' in this section are derived from all the recipes assigned in the set and are will be applied to the Avatar when the wardrobe sets recipes are added.", MessageType.Info);
                    if (_compatibleRaces.Count > 0)
                    {
                        //dont show shared colors unless there are 'FullOutfits' to apply them to
                        if (_sharedColorsEditor.OnGUI(_recipe))
                        {
                            changed       = true;
                            _textureDirty = true;
                        }
                        for (int i = 0; i < _compatibleRaces.Count; i++)
                        {
                            var thisRace = context.raceLibrary.GetRace(_compatibleRaces[i]);
                            if (thisRace != null)
                            {
                                GUILayout.BeginHorizontal(EditorStyles.toolbarButton);
                                GUILayout.Space(10);
                                bool foldoutOpen = OpenSlots[_compatibleRaces[i]];
                                foldoutOpen = EditorGUILayout.Foldout(OpenSlots[_compatibleRaces[i]], " Wardrobe Set: " + _compatibleRaces[i]);
                                OpenSlots[_compatibleRaces[i]] = foldoutOpen;
                                GUILayout.EndHorizontal();
                                if (foldoutOpen)
                                {
                                    var thisSetEditor = new WardrobeSetEditor(thisRace, _wardrobeCollection[thisRace.raceName], _recipe, false);
                                    if (thisSetEditor.OnGUI())
                                    {
                                        _wardrobeCollection[thisRace.raceName] = thisSetEditor.WardrobeSet;
                                        changed = true;
                                    }
                                }
                            }
                            else
                            {
                                //Do the foldout thing but show as 'missing'
                                GUILayout.BeginHorizontal(EditorStyles.toolbarButton);
                                GUILayout.Space(10);
                                bool foldoutOpen = OpenSlots[_compatibleRaces[i]];
                                foldoutOpen = EditorGUILayout.Foldout(OpenSlots[_compatibleRaces[i]], _compatibleRaces[i] + " Wardrobe Set (Missing)");
                                OpenSlots[_compatibleRaces[i]] = foldoutOpen;
                                GUILayout.EndHorizontal();
                                if (foldoutOpen)
                                {
                                    GUIHelper.BeginVerticalPadded(10, new Color(0.75f, 0.875f, 1f));
                                    EditorGUILayout.HelpBox("_compatibleRaces[i] could not be located by the Dynamic Race Library", MessageType.Warning);
                                    GUIHelper.EndVerticalPadded(10);
                                }
                            }
                        }
                    }
                    else
                    {
                        EditorGUILayout.HelpBox("Drag in compatible races at the top of this recipe and WardrobeSets for those races will show here", MessageType.Info);
                    }
                    GUIHelper.EndVerticalPadded(10);
                }
                GUILayout.Space(10);
                //the Arbitrary Recipes section
                GUILayout.BeginHorizontal(EditorStyles.toolbarButton);
                GUILayout.Space(10);
                bool arbiOpen = OpenSlots["arbitraryRecipes"];

                arbiOpen = EditorGUILayout.Foldout(OpenSlots["arbitraryRecipes"], "Arbitrary Recipes");
                OpenSlots["arbitraryRecipes"] = arbiOpen;
                Rect dropArea = new Rect();

                GUILayout.EndHorizontal();
                if (arbiOpen)
                {
                    GUIHelper.BeginVerticalPadded(10, new Color(0.75f, 0.875f, 1f));
                    EditorGUILayout.HelpBox("Drop recipes in to this area to create a collection that is not a full outfit or connected to any given race, for example a 'Hair Styles' pack or 'Tattoos' pack.", MessageType.Info);
                    dropArea = GUILayoutUtility.GetRect(0.0f, 50.0f, GUILayout.ExpandWidth(true));
                    GUI.Box(dropArea, "Drag WardrobeRecipes here. " + recipesAddErrMsg);
                    if (_arbitraryRecipes.Count > 0)
                    {
                        for (int i = 0; i < _arbitraryRecipes.Count; i++)
                        {
                            GUILayout.Space(2f);
                            GUI.enabled = false;                             //we readonly to prevent typos
                            Rect crfRect    = GUILayoutUtility.GetRect(0.0f, EditorGUIUtility.singleLineHeight, GUILayout.ExpandWidth(true));
                            Rect crfDelRect = crfRect;
                            crfRect.width    = crfRect.width - 20f - 5f;
                            crfDelRect.width = 20f + 2f;
                            crfDelRect.x     = crfRect.width + 20f + 10f;
                            EditorGUI.TextField(crfRect, _arbitraryRecipes[i]);
                            GUI.enabled = true;
                            if (GUI.Button(crfDelRect, "X"))
                            {
                                _arbitraryRecipes.RemoveAt(i);
                                changed = true;
                            }
                        }
                    }
                    GUIHelper.EndVerticalPadded(10);
                    if (AddRecipesDropAreaGUI(ref recipesAddErrMsg, dropArea, _arbitraryRecipes))
                    {
                        changed = true;
                    }
                }
                return(changed);
            }
예제 #8
0
    public static GameObject CreateEditorContext()
    {
        GameObject EditorUMAContext = null;

        if (UnityEditor.BuildPipeline.isBuildingPlayer)
        {
            return(null);
        }
        if (Application.isPlaying)
        {
            Debug.LogWarning("There was no UMAContext in this scene. Please add the UMA_DCS prefab to this scene before you try to generate an UMA.");
            return(null);
        }
        Debug.Log("UMA Recipe Editor created an UMAEditorContext to enable editing. This will auto delete once you have finished editing your recipe or you add the UMA_DCS prefab to this scene.");
        //if there is already an UMAEditorContext use it
        if (UMAContext.FindInstance() != null)
        {
            if (UMAContext.FindInstance().gameObject.name == "UMAEditorContext")
            {
                EditorUMAContext = UMAContext.FindInstance().gameObject;
                //if the UMAContext itself is on this game object, it means this was created and not deleted by the previous version of 'CreateEditorContext'
                //(The new version creates the UMAContext on a child game object called 'UMAContext' so that UMAContext.FindInstance can find it properly)
                //so in this case delete all the components that would have been added from the found gameObject from the previous code
                if (EditorUMAContext.GetComponent <UMAContext>())
                {
                    Destroy(EditorUMAContext.GetComponent <UMAContext>());                   //should also make the instance null again
                    if (EditorUMAContext.GetComponent <DynamicRaceLibrary>())
                    {
                        Destroy(EditorUMAContext.GetComponent <DynamicRaceLibrary>());
                    }
                    if (EditorUMAContext.GetComponent <DynamicSlotLibrary>())
                    {
                        Destroy(EditorUMAContext.GetComponent <DynamicSlotLibrary>());
                    }
                    if (EditorUMAContext.GetComponent <DynamicOverlayLibrary>())
                    {
                        Destroy(EditorUMAContext.GetComponent <DynamicOverlayLibrary>());
                    }
                    if (EditorUMAContext.GetComponent <DynamicCharacterSystem>())
                    {
                        Destroy(EditorUMAContext.GetComponent <DynamicCharacterSystem>());
                    }
                    if (EditorUMAContext.GetComponent <DynamicAssetLoader>())
                    {
                        Destroy(EditorUMAContext.GetComponent <DynamicAssetLoader>());
                    }
                }
            }
            else if (UMAContext.FindInstance().gameObject.transform.parent.gameObject.name == "UMAEditorContext")
            {
                EditorUMAContext = UMAContext.FindInstance().gameObject.transform.parent.gameObject;
            }
        }
        else if (GameObject.Find("UMAEditorContext"))
        {
            EditorUMAContext = GameObject.Find("UMAEditorContext");
        }
        else
        {
            EditorUMAContext      = new GameObject();
            EditorUMAContext.name = "UMAEditorContext";
        }
        //Make this GameObject not show up in the scene or save
        EditorUMAContext.hideFlags = HideFlags.DontSave | HideFlags.NotEditable;
        //if this gameobject does not contain an UMAContext add it - we have to call it UMAContext because UMAContext.FindInstance searches for that game object
        var thisUMAContext = UMAContext.Instance = EditorUMAContext.GetComponentInChildren <UMAContext>();

        if (UMAContext.Instance == null)
        {
            var thisUMAContextGO = new GameObject();
            thisUMAContextGO.name             = "UMAContext";
            thisUMAContextGO.transform.parent = EditorUMAContext.transform;
            thisUMAContext      = thisUMAContextGO.AddComponent <UMAContext>();
            UMAContext.Instance = thisUMAContext;
        }
        //we need to add the libraries as components of the game object too
        //and then set THOSE components to the umaContext component
        thisUMAContext.raceLibrary = thisUMAContext.gameObject.AddComponent <DynamicRaceLibrary>();
        (thisUMAContext.raceLibrary as DynamicRaceLibrary).dynamicallyAddFromResources    = true;
        (thisUMAContext.raceLibrary as DynamicRaceLibrary).dynamicallyAddFromAssetBundles = true;
        thisUMAContext.overlayLibrary = thisUMAContext.gameObject.AddComponent <DynamicOverlayLibrary>();
        (thisUMAContext.overlayLibrary as DynamicOverlayLibrary).dynamicallyAddFromResources    = true;
        (thisUMAContext.overlayLibrary as DynamicOverlayLibrary).dynamicallyAddFromAssetBundles = true;
        thisUMAContext.slotLibrary = thisUMAContext.gameObject.AddComponent <DynamicSlotLibrary>();
        (thisUMAContext.slotLibrary as DynamicSlotLibrary).dynamicallyAddFromResources    = true;
        (thisUMAContext.slotLibrary as DynamicSlotLibrary).dynamicallyAddFromAssetBundles = true;
        thisUMAContext.dynamicCharacterSystem = thisUMAContext.gameObject.AddComponent <UMACharacterSystem.DynamicCharacterSystem>();
        (thisUMAContext.dynamicCharacterSystem as DynamicCharacterSystem).dynamicallyAddFromResources    = true;
        (thisUMAContext.dynamicCharacterSystem as DynamicCharacterSystem).dynamicallyAddFromAssetBundles = true;
        var thisDAL = thisUMAContext.gameObject.AddComponent <DynamicAssetLoader>();

        DynamicAssetLoader.Instance = thisDAL;
        return(EditorUMAContext);
    }
예제 #9
0
 private void AddAdditionalSlots()
 {
     umaData.AddAdditionalRecipes(additionalRecipes, UMAContext.FindInstance());
 }
예제 #10
0
 public CharacterSlotOverly(UMADynamicAvatar _umaDynamicAvatar)
 {
     umaDynamicAvatar = _umaDynamicAvatar;
     umaContext       = UMAContext.FindInstance();
 }
        public bool AddExtraStuff()
        {
            SerializedProperty baseRaceRecipe = serializedObject.FindProperty("baseRaceRecipe");

            EditorGUI.BeginChangeCheck();
            EditorGUILayout.PropertyField(baseRaceRecipe, true);
            if (EditorGUI.EndChangeCheck())
            {
                serializedObject.ApplyModifiedProperties();
            }
            if (wardrobeSlotList == null)
            {
                InitWardrobeSlotList();
            }

            EditorGUILayout.Space();

            EditorGUI.BeginChangeCheck();
            wardrobeSlotList.DoLayoutList();
            if (EditorGUI.EndChangeCheck())
            {
                serializedObject.ApplyModifiedProperties();
                if (!race.ValidateWardrobeSlots())
                {
                    EditorUtility.SetDirty(race);
                }
            }
            //new CrossCompatibilitySettings
            //To push any old settings in RaceData.backwardsCompatibleWith into the new crossCompatibilitySettings we have to call GetCrossCompatibleRaces() directly on the target
#pragma warning disable 618
            if (race.backwardsCompatibleWith.Count > 0)
            {
                var cc = race.GetCrossCompatibleRaces();
                if (cc.Count > 0)
                {
                    serializedObject.Update();
                }
            }
#pragma warning restore 618
            SerializedProperty _crossCompatibilitySettings     = serializedObject.FindProperty("_crossCompatibilitySettings");
            SerializedProperty _crossCompatibilitySettingsData = _crossCompatibilitySettings.FindPropertyRelative("settingsData");
            //draw the new version of the crossCompatibility list that allows users to define what slots in this races base recipe equate to in the backwards compatible races base recipe
            _crossCompatibilitySettings.isExpanded = EditorGUILayout.Foldout(_crossCompatibilitySettings.isExpanded, "Cross Compatibility Settings");
            if (_crossCompatibilitySettings.isExpanded)
            {
                //draw an info foldout
                EditorGUI.indentLevel++;
                _crossCompatibilitySettingsData.isExpanded = EditorGUILayout.Foldout(_crossCompatibilitySettingsData.isExpanded, "Help");
                if (_crossCompatibilitySettingsData.isExpanded)
                {
                    var helpText = "CrossCompatibilitySettings allows this race to wear wardrobe slots from another race, if this race has a wardrobe slot that the recipe is set to.";
                    helpText += " You can further configure the compatibility settings for each compatible race to define 'equivalent' slotdatas in the races' base recipes.";
                    helpText += " For example you could define that this races 'highpolyMaleChest' slotdata in its base recipe is equivalent to HumanMales 'MaleChest' slot data in its base recipe.";
                    helpText += " This would mean that any recipes which hid or applied an overlay to 'MaleChest' would hide or apply an overlay to 'highPolyMaleChest' on this race.";
                    helpText += " If 'Overlays Match' is unchecked then overlays in a recipe wont be applied.";
                    EditorGUILayout.HelpBox(helpText, MessageType.Info);
                }
                EditorGUI.indentLevel--;
                if (baseRaceRecipe.objectReferenceValue != null)
                {
                    Rect dropArea = new Rect();
                    dropArea = GUILayoutUtility.GetRect(0.0f, 50.0f, GUILayout.ExpandWidth(true));
                    GUI.Box(dropArea, "Drag cross compatible Races here. Click to pick.");
                    CompatibleRacesDropArea(dropArea, _crossCompatibilitySettingsData);
                    EditorGUILayout.Space();
                    //update the foldouts list if the dropbox changes anything
                    if (_BCFoldouts.Length != _crossCompatibilitySettingsData.arraySize)
                    {
                        Array.Resize <bool>(ref _BCFoldouts, _crossCompatibilitySettingsData.arraySize);
                    }
                    //we need an uptodate list of the slots in THIS races base recipe
                    baseSlotsList.Clear();
                    baseSlotsNamesList.Clear();
                    //editing a race will require a context too because we need to get the base recipes and their slots
                    if (UMAContext.FindInstance() == null)
                    {
                        EditorUMAContext = UMAContext.CreateEditorContext();
                    }
                    UMAData.UMARecipe thisBaseRecipe = (baseRaceRecipe.objectReferenceValue as UMARecipeBase).GetCachedRecipe(UMAContext.Instance);
                    SlotData[]        thisBaseSlots  = thisBaseRecipe.GetAllSlots();
                    foreach (SlotData slot in thisBaseSlots)
                    {
                        if (slot != null)
                        {
                            baseSlotsList.Add(slot);
                            baseSlotsNamesList.Add(slot.slotName);
                        }
                    }
                    List <int> crossCompatibleSettingsToDelete = new List <int>();
                    //draw a foldout area for each compatible race that will show an entry for each slot in this races base recipe
                    //with a picker to choose the slot from the compatible race's base recipe that it equates to
                    for (int i = 0; i < _crossCompatibilitySettingsData.arraySize; i++)
                    {
                        bool del            = false;
                        var  thisCCSettings = _crossCompatibilitySettingsData.GetArrayElementAtIndex(i).FindPropertyRelative("ccSettings");
                        var  ccRaceName     = _crossCompatibilitySettingsData.GetArrayElementAtIndex(i).FindPropertyRelative("ccRace").stringValue;
                        //this could be missing- we should show that
                        var label = ccRaceName;
                        if (GetCompatibleRaceData(ccRaceName) == null)
                        {
                            label += " (missing)";
                        }
                        GUIHelper.FoldoutBar(ref _BCFoldouts[i], label, out del);
                        if (del)
                        {
                            crossCompatibleSettingsToDelete.Add(i);
                        }
                        if (_BCFoldouts[i])
                        {
                            DrawCCUI(ccRaceName, baseRaceRecipe, thisCCSettings);
                        }
                    }
                    if (crossCompatibleSettingsToDelete.Count > 0)
                    {
                        foreach (int del in crossCompatibleSettingsToDelete)
                        {
                            _crossCompatibilitySettingsData.DeleteArrayElementAtIndex(del);
                            serializedObject.ApplyModifiedProperties();
                        }
                    }
                }
                else
                {
                    EditorGUILayout.HelpBox("Please define this races baseRaceRecipe before trying to define its cross compatibility settings.", MessageType.Info);
                }
            }

            EditorGUILayout.Space();

            EditorGUI.BeginChangeCheck();
            EditorGUILayout.PropertyField(serializedObject.FindProperty("raceThumbnails"), true);
            if (EditorGUI.EndChangeCheck())
            {
                serializedObject.ApplyModifiedProperties();
            }
            return(false);
        }
예제 #12
0
        public override void OnInspectorGUI()
        {
            serializedObject.Update();
            MeshHideAsset source            = target as MeshHideAsset;
            bool          beginSceneEditing = false;

            //DrawDefaultInspector();
            SlotDataAsset obj = EditorGUILayout.ObjectField("SlotDataAsset", source.asset, typeof(SlotDataAsset), false) as SlotDataAsset;

            if (obj != source.asset)
            {
                source.asset = obj as SlotDataAsset;
                if (_autoInitialize)
                {
                    UpdateSourceAsset(obj);
                }
            }
            EditorGUILayout.LabelField("Slot Name", source.AssetSlotName.ToString());

            _autoInitialize = EditorGUILayout.Toggle(new GUIContent("AutoInitialize (recommended)", "Checking this will auto initialize the MeshHideAsset when a slot is added (recommended).  " +
                                                                    "For users that are rebuilding slots that don't change the geometry, the slot reference will be lost but can be reset without losing the existing MeshHide information by unchecking this."), _autoInitialize);

            if (source.asset == null)
            {
                EditorGUILayout.HelpBox("No SlotDataAsset set! Begin by adding a SlotDataAsset to the object field above.", MessageType.Error);
            }


            //Race Selector here
            GUILayout.Space(20);
            selectedRaceIndex = EditorGUILayout.Popup("Select Base Slot by Race", selectedRaceIndex, foundRaceNames.ToArray());
            if (selectedRaceIndex <= 0)
            {
                EditorGUILayout.HelpBox("Quick selection of base slots by race. This is not needed to create a mesh hide asset, any slot can be used.", MessageType.Info);
            }
            else
            {
                UMAData.UMARecipe baseRecipe = new UMAData.UMARecipe();
                foundRaces[selectedRaceIndex].baseRaceRecipe.Load(baseRecipe, UMAContext.FindInstance());

                foreach (SlotData sd in baseRecipe.slotDataList)
                {
                    if (sd != null && sd.asset != null)
                    {
                        if (GUILayout.Button(string.Format("{0} ({1})", sd.asset.name, sd.slotName)))
                        {
                            if (UpdateSourceAsset(sd.asset))
                            {
                                selectedRaceIndex = 0;
                            }
                        }
                    }
                }
            }

            GUILayout.Space(20);
            if (source.TriangleCount > 0)
            {
                EditorGUILayout.LabelField("Triangle Indices Count: " + source.TriangleCount);
                EditorGUILayout.LabelField("Submesh Count: " + source.SubmeshCount);
                EditorGUILayout.LabelField("Hidden Triangle Count: " + source.HiddenCount);
            }
            else
            {
                EditorGUILayout.LabelField("No triangle array found");
            }

            GUILayout.Space(20);
            if (!GeometrySelectorWindow.IsOpen)
            {
                EditorGUI.BeginDisabledGroup(source.asset == null);
                if (GUILayout.Button("Begin Editing", GUILayout.MinHeight(50)))
                {
                    if (source.asset != null)
                    {
                        beginSceneEditing = true;
                    }
                }
                EditorGUI.EndDisabledGroup();
                GUILayout.Space(20);
                GUILayout.Label("Editing will be done in an empty scene.");
                GUILayout.Label("You will be prompted to save the scene");
                GUILayout.Label("if there are any unsaved changes.");
            }
            serializedObject.ApplyModifiedProperties();

            if (beginSceneEditing)
            {
                // This has to happen outside the inspector
                EditorApplication.delayCall += CreateSceneEditObject;
            }
        }
예제 #13
0
        public void OnEnable()
        {
            if (!NeedsReenable())
            {
                return;
            }

            _errorMessage  = null;
            _recipe        = new UMAData.UMARecipe();
            showBaseEditor = false;

            try
            {
                var umaRecipeBase = target as UMARecipeBase;
                if (umaRecipeBase != null)
                {
                    //if we dont have an umaContext the recipe wont actually load and we dont want people to edit it because it wont save properly
                    //01022016 BUT we do still ned to output the inspector or else people cant make new recipes when they have a scene open with no UMAContext
                    //TODO work out a way of editing recipes when there ISNT an UMA Context
                    var context = UMAContext.FindInstance();
                    if (context == null)
                    {
                        context          = umaRecipeBase.CreateEditorContext();
                        generatedContext = context.gameObject;
                    }
                    if (context == null)
                    {
                        context       = umaRecipeBase.CreateEditorContext();
                        _errorMessage = "Editing a recipe requires a loaded scene with a valid UMAContext.";
                        Debug.LogWarning(_errorMessage);
                        //_recipe = null;
                        //return;
                    }
                    else if (context.raceLibrary == null)
                    {
                        _errorMessage = "Editing a recipe requires a loaded scene with a valid UMAContext with RaceLibrary assigned.";
                        Debug.LogWarning(_errorMessage);
                        //_recipe = null;
                        //return;
                    }
                    //when the recipe loads it can be really slow the first time can we show a notification?
                    //this doesn't bloody show quick enough though
                    //var editorAssembly = typeof(Editor).Assembly;
                    //var inspectorWindowType = editorAssembly.GetType("UnityEditor.InspectorWindow");
                    //inspectorWindow = EditorWindow.GetWindow(inspectorWindowType);
                    //if(inspectorWindow != null)
                    //inspectorWindow.ShowNotification(new GUIContent("UMA is gathering Data.."));
                    //this is where we are waiting, but the notification does not show before this starts
                    umaRecipeBase.Load(_recipe, context);
                    _description = umaRecipeBase.GetInfo();

                    //if (inspectorWindow != null)
                    //	inspectorWindow.RemoveNotification();
                }
            }
            catch (UMAResourceNotFoundException e)
            {
                _errorMessage = e.Message;
            }

            dnaEditor  = new DNAMasterEditor(_recipe);
            slotEditor = new SlotMasterEditor(_recipe);

            _rebuildOnLayout = true;
        }
예제 #14
0
            public bool OnGUI()
            {
                bool changed = false;

                if (_race != null)
                {
                    if (_race.wardrobeSlots.Count > 0)
                    {
                        var context = UMAContext.FindInstance();
                        if (context == null)
                        {
                            var _errorMessage = "Editing a recipe requires a loaded scene with a valid UMAContext.";
                            Debug.LogWarning(_errorMessage);
                        }

                        if (_wardrobeSet == null || context == null)
                        {
                            return(false);
                        }
                        GUIHelper.BeginVerticalPadded(10, new Color(0.75f, 0.875f, 1f));

                        EditorGUILayout.HelpBox("Recently added recipes not showing up? Make sure you have added them to the 'UMA Global Library' and click the 'Refresh Recipes' button below.", MessageType.Info);
                        if (GUILayout.Button("Refresh Recipes"))
                        {
                            context.dynamicCharacterSystem.Refresh(false);
                            return(false);
                        }
                        //a dictionary of slots that are being assigned by WardrobeCollections
                        var slotsAssignedByWCs = new Dictionary <string, string>();
                        if (_allowWardrobeCollectionSlot)
                        {
                            var wcRecipesForRace = context.dynamicCharacterSystem.GetRecipesForRaceSlot(_race.raceName, "WardrobeCollection");
                            var wcGroupDict      = new Dictionary <string, List <UMARecipeBase> >();
                            //I'm using reflection here to get fields and methods from the UMAWardrobeCollection type so this will still work if 'StandardAssets' is moved to 'Standard Assets'
                            for (int i = 0; i < wcRecipesForRace.Count; i++)
                            {
                                Type wcType = wcRecipesForRace[i].GetType();
                                if (wcType.ToString().Replace(wcType.Namespace + ".", "") == "UMAWardrobeCollection")
                                {
                                    FieldInfo wcRecipeSlotField = wcType.GetField("wardrobeSlot", BindingFlags.Public | BindingFlags.Instance);
                                    var       wcRecipeSlot      = (string)wcRecipeSlotField.GetValue(wcRecipesForRace[i]);
                                    if (!wcGroupDict.ContainsKey(wcRecipeSlot))
                                    {
                                        wcGroupDict.Add(wcRecipeSlot, new List <UMARecipeBase>());
                                    }
                                    wcGroupDict[wcRecipeSlot].Add(wcRecipesForRace[i]);
                                }
                            }
                            if (wcGroupDict.Count > 0)
                            {
                                MethodInfo WCGetRacesWardrobeSetMethod = null;
                                EditorGUILayout.LabelField("WardrobeCollections");
                                EditorGUI.indentLevel++;
                                foreach (KeyValuePair <string, List <UMARecipeBase> > kp in wcGroupDict)
                                {
                                    if (WCGetRacesWardrobeSetMethod == null)
                                    {
                                        WCGetRacesWardrobeSetMethod = kp.Value[0].GetType().GetMethod("GetRacesWardrobeSet", new Type[] { typeof(RaceData) });
                                    }
                                    var selected      = 0;
                                    var prevRecipe    = "";
                                    var thisPopupVals = new List <string>();
                                    thisPopupVals.Add("None");
                                    for (int i = 0; i < kp.Value.Count; i++)
                                    {
                                        thisPopupVals.Add(kp.Value[i].name);
                                        //check if this is selected
                                        for (int wsi = 0; wsi < _wardrobeSet.Count; wsi++)
                                        {
                                            if (kp.Value[i].name == _wardrobeSet[wsi].recipe)
                                            {
                                                prevRecipe = _wardrobeSet[wsi].recipe;
                                                selected   = i + 1;
                                                var thisWCWardrobeSet = (List <WardrobeSettings>)WCGetRacesWardrobeSetMethod.Invoke(kp.Value[i], new object[] { _race });
                                                for (int wcwsi = 0; wcwsi < thisWCWardrobeSet.Count; wcwsi++)
                                                {
                                                    if (!slotsAssignedByWCs.ContainsKey(thisWCWardrobeSet[wcwsi].slot))
                                                    {
                                                        slotsAssignedByWCs.Add(thisWCWardrobeSet[wcwsi].slot, kp.Value[i].name);
                                                    }
                                                    else
                                                    {
                                                        slotsAssignedByWCs[thisWCWardrobeSet[wcwsi].slot] = kp.Value[i].name;
                                                    }
                                                }
                                                break;
                                            }
                                        }
                                    }
                                    EditorGUI.BeginChangeCheck();
                                    var newSelected = EditorGUILayout.Popup(kp.Key, selected, thisPopupVals.ToArray());
                                    if (EditorGUI.EndChangeCheck())
                                    {
                                        for (int wsi = 0; wsi < _wardrobeSet.Count; wsi++)
                                        {
                                            if (_wardrobeSet[wsi].recipe == prevRecipe)
                                            {
                                                //we need to remove the wardrobeSettings that has prevRecipe as its value from _wardrobeSettings
                                                if (newSelected == 0)
                                                {
                                                    _wardrobeSet.RemoveAt(wsi);
                                                }
                                                else
                                                {
                                                    //we need to make wardrobeSettings that has prevRecipe have the new value
                                                    _wardrobeSet[wsi].recipe = thisPopupVals[newSelected];
                                                }
                                            }
                                        }
                                        changed = true;
                                    }
                                }
                                EditorGUI.indentLevel--;
                                EditorGUILayout.Space();
                                EditorGUILayout.LabelField("WardrobeSlots");
                                EditorGUI.indentLevel++;
                            }
                        }
                        foreach (string wsl in _race.wardrobeSlots)
                        {
                            if (wsl == "None")
                            {
                                continue;
                            }

                            //Obsolete- now wardrobeCollections apply their WardrobeSet to any slots
                            //if (wsl == "FullOutfit" && _allowWardrobeCollectionSlot == false)
                            //	continue;

                            WardrobeSlotRecipePopup thisPicker = null;
                            bool assignedPicker = false;
                            for (int wsi = 0; wsi < _wardrobeSet.Count; wsi++)
                            {
                                if (_wardrobeSet[wsi].slot == wsl)
                                {
                                    thisPicker     = new WardrobeSlotRecipePopup(_race.raceName, wsl, _wardrobeSet[wsi].recipe);
                                    assignedPicker = true;
                                    break;
                                }
                            }
                            if (!assignedPicker)                            //means there was nothing in the wardrobe set for it
                            {
                                //This may still be being assigned by a wardrobe collection though so show that
                                var wcOverrideName = "";
                                if (slotsAssignedByWCs.ContainsKey(wsl))
                                {
                                    wcOverrideName = slotsAssignedByWCs[wsl];
                                }
                                thisPicker = new WardrobeSlotRecipePopup(_race.raceName, wsl, "");
                            }
                            if (thisPicker.OnGUI())
                            {
                                changed = true;
                                if (thisPicker.RecipeName != "None" && thisPicker.RecipeName != "")
                                {
                                    bool contained = false;
                                    for (int i = 0; i < _wardrobeSet.Count; i++)
                                    {
                                        if (_wardrobeSet[i].slot == wsl)
                                        {
                                            _wardrobeSet[i].recipe = thisPicker.RecipeName;
                                            contained = true;
                                            break;
                                        }
                                    }
                                    if (!contained)
                                    {
                                        _wardrobeSet.Add(new WardrobeSettings(wsl, thisPicker.RecipeName));
                                    }
                                }
                                else
                                {
                                    for (int i = 0; i < _wardrobeSet.Count; i++)
                                    {
                                        if (_wardrobeSet[i].slot == wsl)
                                        {
                                            _wardrobeSet.RemoveAt(i);
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                        if (_allowWardrobeCollectionSlot)
                        {
                            EditorGUI.indentLevel--;
                        }
                        if (WardrobeSet.Count > 0)
                        {
                            EditorGUILayout.Space();
                            if (GUILayout.Button(new GUIContent("UpdateSharedColors", "Automatically adds any shared colors defined in the selected recipes to this recipes SharedColors")))
                            {
                                for (int i = 0; i < _wardrobeSet.Count; i++)
                                {
                                    changed = AddSharedColorsFromRecipe(_wardrobeSet[i].recipe, _recipe) == true ? true : changed;
                                }
                            }
                        }
                        GUIHelper.EndVerticalPadded(10);
                    }
                }
                return(changed);
            }