Beispiel #1
0
        /// <summary>
        /// Draws an object field with an 'inspect' button next to it which opens up the editor for the assigned object in a popup window
        /// </summary>
        public static void InspectableObjectField(Rect position, SerializedProperty property, GUIContent label, UnityAction <EditorWindow> onCreateWindowCallback = null)
        {
            label = EditorGUI.BeginProperty(position, label, property);
            var objectFieldRect = position;
            var inspectBtnRect  = Rect.zero;

            if (property.objectReferenceValue)
            {
                objectFieldRect = new Rect(position.xMin, position.yMin, position.width - inspectBtnWidth - 4f, position.height);
                inspectBtnRect  = new Rect(objectFieldRect.xMax + 4f, objectFieldRect.yMin, inspectBtnWidth, objectFieldRect.height);
            }
            EditorGUI.ObjectField(objectFieldRect, property, label);
            if (property.objectReferenceValue)
            {
                if (GUI.Button(inspectBtnRect, inspectContent, inspectStyle))
                {
                    var inspectorWindow = InspectorUtlity.InspectTarget(property.objectReferenceValue);
                    if (onCreateWindowCallback != null)
                    {
                        onCreateWindowCallback(inspectorWindow);
                    }
                }
            }
            EditorGUI.EndProperty();
        }
Beispiel #2
0
        void CellGUI(Rect cellRect, TreeViewItem <AssetTreeElement> item, AssetColumns column, ref RowGUIArgs args)
        {
            // Center cell rect vertically (makes it easier to place controls, icons etc in the cells)
            CenterRectUsingSingleLineHeight(ref cellRect);

            if (item.data.depth == 0)
            {
                HeaderCellGUI(cellRect, item, column, ref args);
                return;
            }

            AssetItem        ai      = item.data.ai;
            AssetTreeElement element = item.data;

            switch (column)
            {
            case AssetColumns.Selection:
            {
                // EditorGUI.Toggle(cellRect, item.data.ai._SerializedItem != null);
                bool newVal = EditorGUI.Toggle(cellRect, element.Checked);
                if (newVal != element.Checked)
                {
                    element.Checked = newVal;
                    RecalcTypeChecks(element.type);
                }
            }
            break;

            case AssetColumns.Type:
            {
                EditorGUI.LabelField(cellRect, element.type.Name);
            }
            break;

            case AssetColumns.Always:
            {
                cellRect.x     += kCheckboxOffset;
                cellRect.width -= kCheckboxOffset;
                bool clicked = EditorGUI.Toggle(cellRect, ai.IsAlwaysLoaded);
                if (clicked != ai.IsAlwaysLoaded)
                {
                    ai.IsAlwaysLoaded = clicked;
                    UMAAssetIndexer.Instance.ForceSave();
                }
            }
            break;

            case AssetColumns.IsResource:
            {
                cellRect.x     += kCheckboxOffset;
                cellRect.width -= kCheckboxOffset;
                EditorGUI.Toggle(cellRect, ai.IsResource);
            }
            break;

            case AssetColumns.Name:
            {
                // Do toggle
                Rect toggleRect = cellRect;
                toggleRect.x    += GetContentIndent(item);
                toggleRect.width = kToggleWidth;
                //if (toggleRect.xMax < cellRect.xMax)
                //	item.data.enabled = EditorGUI.Toggle(toggleRect, item.data.enabled); // hide when outside cell rect

                // Default icon and label
                args.rowRect = cellRect;
                base.RowGUI(args);
            }
            break;

            case AssetColumns.IsAddressable:
            {
                cellRect.x     += kCheckboxOffset;
                cellRect.width -= kCheckboxOffset;
                EditorGUI.Toggle(cellRect, ai.IsAddressable);
            }
            break;

            case AssetColumns.Group:
                EditorGUI.LabelField(cellRect, ai.AddressableGroup);
                break;

            case AssetColumns.Labels:
            {
                if (!string.IsNullOrEmpty(ai.AddressableLabels))
                {
                    Rect Button = new Rect(cellRect);
                    Button.width   = 32;
                    Button.height -= 2;

                    if (GUI.Button(Button, "View", EditorStyles.toolbarButton))
                    {
                        List <string> labels = new List <string>();
                        labels.AddRange(ai.AddressableLabels.Split(';'));
                        DisplayListWindow.ShowDialog("Addressable Labels", owningWindow.position, labels);
                    }
                    cellRect.x     += 32;
                    cellRect.width -= 32;
                    EditorGUI.LabelField(cellRect, ai.AddressableLabels);
                }
            }
            break;

            case AssetColumns.Buttons:
            {
                float BtnWidth   = (cellRect.width / 3) - (kToggleWidth * 2);
                Rect  ButtonRect = new Rect(cellRect);
                ButtonRect.width = BtnWidth;

                if (GUI.Button(ButtonRect, "Inspect", EditorStyles.toolbarButton))
                {
                    UnityEngine.Object o = AssetDatabase.LoadMainAssetAtPath(ai._Path);
                    InspectorUtlity.InspectTarget(o);
                }

                /*
                 * ButtonRect.x = ButtonRect.x + BtnWidth;
                 * if (item.data.ai._SerializedItem == null)
                 * {
                 *      if(GUI.Button(ButtonRect, "Add Ref", EditorStyles.toolbarButton))
                 *      {
                 *              ai.CacheSerializedItem();
                 *              Repaint();
                 *      }
                 * }
                 * else
                 * {
                 *      if(GUI.Button(ButtonRect, "Rmv Ref",EditorStyles.toolbarButton))
                 *      {
                 *              ai.ReleaseItem();
                 *              Repaint();
                 *      }
                 * }
                 */
#if UMA_ADDRESSABLES
                if (ai.Item is UMATextRecipe)
                {
                    UMATextRecipe recipe = ai.Item as UMATextRecipe;

                    if (owningWindow.LoadedLabels.Contains(recipe.AssignedLabel))
                    {
                        ButtonRect.x     = ButtonRect.x + ButtonRect.width;
                        ButtonRect.width = 110;

                        if (GUI.Button(ButtonRect, "Update Groups", EditorStyles.toolbarButton))
                        {
                            UMAAssetIndexer.Instance.AddRecipeGroup(recipe);
                            owningWindow.LoadedLabels.Add(recipe.AssignedLabel);
                        }
                    }
                    else
                    {
                        ButtonRect.x     = ButtonRect.x + ButtonRect.width;
                        ButtonRect.width = 110;

                        if (GUI.Button(ButtonRect, "Make Addressable", EditorStyles.toolbarButton))
                        {
                            UMAAssetIndexer.Instance.AddRecipeGroup(recipe);
                            owningWindow.LoadedLabels.Add(recipe.AssignedLabel);
                        }
                    }
                }
#endif
                ButtonRect.x     = ButtonRect.x + ButtonRect.width;
                ButtonRect.width = 32;
                if (GUI.Button(ButtonRect, "Ping", EditorStyles.toolbarButton))
                {
                    UnityEngine.Object o = AssetDatabase.LoadMainAssetAtPath(ai._Path);
                    EditorGUIUtility.PingObject(o);
                }

                ButtonRect.x     = ButtonRect.x + 32;
                ButtonRect.width = kToggleWidth;
                if (GUI.Button(ButtonRect, "X", EditorStyles.toolbarButton))
                {
                    // remove from index.
                    // remove from tree.

                    List <AssetTreeElement> RemoveMe = new List <AssetTreeElement>();
                    UMAAssetIndexer.Instance.RemoveAsset(ai._Type, ai._Name);
                    RemoveMe.Add(item.data);
                    this.treeModel.RemoveElements(RemoveMe);
                    owningWindow.RecountTypes();
                    RecalcTypeChecks(element.type);
                    Repaint();
                }
            }
            break;
            }
        }
Beispiel #3
0
        public bool ShowArray(System.Type CurrentType, string Filter)
        {
            bool   HasFilter = false;
            bool   NotFound  = false;
            string actFilter = Filter.Trim().ToLower();

            if (actFilter.Length > 0)
            {
                HasFilter = true;
            }

            Dictionary <string, AssetItem> TypeDic = UAI.GetAssetDictionary(CurrentType);

            if (!TypeCheckboxes.ContainsKey(CurrentType))
            {
                TypeCheckboxes.Add(CurrentType, new List <bool>());
            }

            List <AssetItem> Items = new List <AssetItem>();

            Items.AddRange(TypeDic.Values);

            int NotInBuild   = 0;
            int VisibleItems = 0;

            foreach (AssetItem ai in Items)
            {
                if (ai._SerializedItem == null)
                {
                    NotInBuild++;
                }
                string Displayed = ai.ToString(UMAAssetIndexer.SortOrder);
                if (HasFilter && (!Displayed.ToLower().Contains(actFilter)))
                {
                    continue;
                }
                VisibleItems++;
            }

            if (TypeCheckboxes[CurrentType].Count != VisibleItems)
            {
                TypeCheckboxes[CurrentType].Clear();
                TypeCheckboxes[CurrentType].AddRange(new bool[VisibleItems]);
            }

            NotInBuildCount += NotInBuild;
            GUILayout.BeginHorizontal(EditorStyles.toolbarButton);
            GUILayout.Space(10);
            Toggles[CurrentType] = EditorGUILayout.Foldout(Toggles[CurrentType], CurrentType.Name + ":  " + VisibleItems + "/" + TypeDic.Count + " Item(s). " + NotInBuild + " Not in build.");
            GUILayout.EndHorizontal();



            if (Toggles[CurrentType])
            {
                Items.Sort();
                GUIHelper.BeginVerticalPadded(5, new Color(0.75f, 0.875f, 1f));
                GUILayout.BeginHorizontal();
                GUILayout.Label("Sorted By: " + UMAAssetIndexer.SortOrder, GUILayout.MaxWidth(160));
                foreach (string s in UMAAssetIndexer.SortOrders)
                {
                    if (GUILayout.Button(s, GUILayout.Width(80)))
                    {
                        UMAAssetIndexer.SortOrder = s;
                    }
                }
                GUILayout.EndHorizontal();

                int CurrentVisibleItem = 0;
                foreach (AssetItem ai in Items)
                {
                    string lblBuild = "B-";
                    string lblVal   = ai.ToString(UMAAssetIndexer.SortOrder);
                    if (HasFilter && (!lblVal.ToLower().Contains(actFilter)))
                    {
                        continue;
                    }

                    if (ai._Name == "< Not Found!>")
                    {
                        NotFound = true;
                    }
                    GUILayout.BeginHorizontal(EditorStyles.textField);

                    TypeCheckboxes[CurrentType][CurrentVisibleItem] = EditorGUILayout.Toggle(TypeCheckboxes[CurrentType][CurrentVisibleItem++], GUILayout.Width(20));
                    if (ai._SerializedItem == null)
                    {
                        lblVal  += "<Not in Build>";
                        lblBuild = "B+";
                    }

                    if (GUILayout.Button(lblVal, EditorStyles.label))
                    {
                        Object o = AssetDatabase.LoadMainAssetAtPath(ai._Path);
                        EditorGUIUtility.PingObject(o);
                        Selection.activeObject = o;
                    }

                    if (GUILayout.Button("I", GUILayout.Width(20.0f)))
                    {
                        Object o = AssetDatabase.LoadMainAssetAtPath(ai._Path);
                        InspectorUtlity.InspectTarget(o);
                    }
                    if (GUILayout.Button(lblBuild, GUILayout.Width(35)))
                    {
                        if (ai._SerializedItem == null)
                        {
                            if (!ai.IsAssetBundle)
                            {
                                ai.CachSerializedItem();
                            }
                        }
                        else
                        {
                            ai.ReleaseItem();
                        }
                    }
                    if (GUILayout.Button("-", GUILayout.Width(20.0f)))
                    {
                        DeletedDuringGUI.Add(ai);
                    }
                    GUILayout.EndHorizontal();
                }

                GUILayout.BeginHorizontal();
                if (NotFound)
                {
                    GUILayout.Label("Warning - Some items not found!");
                }
                else
                {
                    GUILayout.Label("All Items appear OK");
                }
                GUILayout.EndHorizontal();

                GUIHelper.BeginVerticalPadded(5, new Color(0.65f, 0.65f, 0.65f));
                GUILayout.Label("Utilities");
                GUILayout.Space(10);

                EditorGUILayout.BeginHorizontal();
                if (GUILayout.Button("Select All"))
                {
                    ProcessItems(CurrentType, null, HasFilter, actFilter, Items, SelectItems);
                }
                if (GUILayout.Button("Select None"))
                {
                    ProcessItems(CurrentType, null, HasFilter, actFilter, Items, DeselectItems);
                }
                EditorGUILayout.EndHorizontal();
                EditorGUILayout.BeginHorizontal();
                if (GUILayout.Button("Remove Checked"))
                {
                    ProcessItems(CurrentType, TypeCheckboxes[CurrentType], HasFilter, actFilter, Items, RemoveChecked);
                }

                if (GUILayout.Button("Force Save"))
                {
                    ProcessItems(CurrentType, TypeCheckboxes[CurrentType], HasFilter, actFilter, Items, ForceSerialize);
                    AssetDatabase.SaveAssets();
                }
                EditorGUILayout.EndHorizontal();


                if (CurrentType == typeof(SlotDataAsset) || CurrentType == typeof(OverlayDataAsset))
                {
                    EditorGUILayout.BeginHorizontal();
                    SelectedMaterial = (UMAMaterial)EditorGUILayout.ObjectField(SelectedMaterial, typeof(UMAMaterial), false);
                    GUILayout.Label("Apply to checked: ");
                    if (GUILayout.Button("Unassigned"))
                    {
                        ProcessItems(CurrentType, TypeCheckboxes[CurrentType], HasFilter, actFilter, Items, SetItemNullMaterial);
                    }
                    if (GUILayout.Button("All"))
                    {
                        ProcessItems(CurrentType, TypeCheckboxes[CurrentType], HasFilter, actFilter, Items, SetItemMaterial);
                    }
                    EditorGUILayout.EndHorizontal();
                }
                GUIHelper.EndVerticalPadded(5);


                GUIHelper.EndVerticalPadded(5);
            }
            return(NotFound);
        }
Beispiel #4
0
        public override void OnInspectorGUI()
        {
            serializedObject.Update();

            EditorGUI.BeginChangeCheck();
            showHelp = EditorGUILayout.Toggle("Show Help", showHelp);
            if (EditorGUI.EndChangeCheck())
            {
                serializedObject.ApplyModifiedProperties();
            }

            Editor.DrawPropertiesExcluding(serializedObject, new string[] { "hide", "BundleCheck", "loadBlendShapes", "activeRace", "defaultChangeRaceOptions", "cacheCurrentState", "rebuildSkeleton", "preloadWardrobeRecipes", "raceAnimationControllers",
                                                                            /* Editor Only Fields */ "editorTimeGeneration",
                                                                            "characterColors", "BoundsOffset", "_buildCharacterEnabled", "keepAvatar", "KeepAnimatorController",
                                                                            /*LoadOtions fields*/ "defaultLoadOptions", "loadPathType", "loadPath", "loadFilename", "loadString", "loadFileOnStart", "waitForBundles", /*"buildAfterLoad",*/
                                                                            /*SaveOptions fields*/ "defaultSaveOptions", "savePathType", "savePath", "saveFilename", "makeUniqueFilename", "ensureSharedColors",
                                                                            /*Moved into AdvancedOptions*/ "context", "umaData", "umaRecipe", "umaAdditionalRecipes", "umaGenerator", "animationController", "defaultRendererAsset",
                                                                            /*Moved into CharacterEvents*/ "CharacterCreated", "CharacterBegun", "CharacterUpdated", "CharacterDestroyed", "CharacterDnaUpdated", "RecipeUpdated", "AnimatorStateSaved", "AnimatorStateRestored", "WardrobeAdded", "WardrobeRemoved",
                                                                            /*PlaceholderOptions fields*/ "showPlaceholder", "previewModel", "customModel", "customRotation", "previewColor", "AtlasResolutionScale", "DelayUnload", "predefinedDNA", "alwaysRebuildSkeleton", "umaRecipe" });

            //The base DynamicAvatar properties- get these early because changing the race changes someof them
            SerializedProperty context              = serializedObject.FindProperty("context");
            SerializedProperty umaData              = serializedObject.FindProperty("umaData");
            SerializedProperty umaGenerator         = serializedObject.FindProperty("umaGenerator");
            SerializedProperty umaRecipe            = serializedObject.FindProperty("umaRecipe");
            SerializedProperty umaAdditionalRecipes = serializedObject.FindProperty("umaAdditionalRecipes");
            SerializedProperty animationController  = serializedObject.FindProperty("animationController");

            // ************************************************************
            // Set the race
            // ************************************************************
            SerializedProperty thisRaceSetter = serializedObject.FindProperty("activeRace");
            Rect currentRect = EditorGUILayout.GetControlRect(false, _racePropDrawer.GetPropertyHeight(thisRaceSetter, GUIContent.none));

            EditorGUI.BeginChangeCheck();
            _racePropDrawer.OnGUI(currentRect, thisRaceSetter, new GUIContent(thisRaceSetter.displayName));
            if (EditorGUI.EndChangeCheck())
            {
                bool okToProcess = true;
                // check to see if we changed it while playing, and if so, don't do it again.
                if (Application.isPlaying)
                {
                    if (thisDCA.activeRace.data != null)
                    {
                        if (thisDCA.activeRace.data.raceName == (string)thisRaceSetter.FindPropertyRelative("name").stringValue)
                        {
                            okToProcess = false;
                        }
                    }
                }

                if (okToProcess)
                {
                    thisDCA.ChangeRace((string)thisRaceSetter.FindPropertyRelative("name").stringValue, DynamicCharacterAvatar.ChangeRaceOptions.useDefaults, true);
                    //Changing the race may cause umaRecipe, animationController to change so forcefully update these too
                    umaRecipe.objectReferenceValue           = thisDCA.umaRecipe;
                    animationController.objectReferenceValue = thisDCA.animationController;
                    serializedObject.ApplyModifiedProperties();
                    GenerateSingleUMA();
                }
            }
            if (showHelp)
            {
                EditorGUILayout.HelpBox("Active Race: Sets the race of the character, which defines the base recipe to build the character, the available DNA, and the available wardrobe.", MessageType.Info);
            }


            //**************************************
            // Begin In-Editor customization
            //**************************************
            showEditorCustomization = EditorGUILayout.Foldout(showEditorCustomization, new GUIContent("Customization", "Properties for customizing the look of the UMA"));

            if (showEditorCustomization)
            {
                BeginVerticalPadded();

                EditorGUILayout.BeginHorizontal();
                if (GUILayout.Button("Save Preset"))
                {
                    string fileName = EditorUtility.SaveFilePanel("Save Preset", "", "DCAPreset", "umapreset");
                    if (!string.IsNullOrEmpty(fileName))
                    {
                        try
                        {
                            UMAPreset prs = new UMAPreset();
                            prs.DefaultColors   = thisDCA.characterColors;
                            prs.PredefinedDNA   = thisDCA.predefinedDNA;
                            prs.DefaultWardrobe = thisDCA.preloadWardrobeRecipes;
                            string presetstring = JsonUtility.ToJson(prs);
                            System.IO.File.WriteAllText(fileName, presetstring);
                        }
                        catch (Exception ex)
                        {
                            Debug.LogException(ex);
                            EditorUtility.DisplayDialog("Error", "Error writing preset file: " + ex.Message, "OK");
                        }
                    }
                }
                if (GUILayout.Button("Load Preset"))
                {
                    string fileName = EditorUtility.OpenFilePanel("Load Preset", "", "umapreset");
                    if (!string.IsNullOrEmpty(fileName))
                    {
                        try
                        {
                            string presetstring = System.IO.File.ReadAllText(fileName);
                            thisDCA.InitializeFromPreset(presetstring);
                            UpdateCharacter();
                        }
                        catch (Exception ex)
                        {
                            Debug.LogException(ex);
                            EditorUtility.DisplayDialog("Error", "Error writing preset file: " + ex.Message, "OK");
                        }
                    }
                }
                if (GUILayout.Button("Save Legacy File"))
                {
                    string fileName = EditorUtility.SaveFilePanel("Save Legacy File", "", "", "crs");
                    if (!string.IsNullOrEmpty(fileName))
                    {
                        try
                        {
                            string charstr = thisDCA.GetCurrentRecipe(false);
                            System.IO.File.WriteAllText(fileName, charstr);
                        }
                        catch (Exception ex)
                        {
                            Debug.LogException(ex);
                            EditorUtility.DisplayDialog("Error", "Error writing preset file: " + ex.Message, "OK");
                        }
                    }
                }
                EditorGUILayout.EndHorizontal();
                EditorGUI.BeginChangeCheck();
                EditorGUILayout.PropertyField(serializedObject.FindProperty("editorTimeGeneration"));
                if (EditorGUI.EndChangeCheck())
                {
                    serializedObject.ApplyModifiedProperties();
                    UpdateCharacter();
                }

                //******************************************************************
                // Preload wardrobe
                //Other DCA propertyDrawers
                //in order for the "preloadWardrobeRecipes" prop to properly check if it can load the recipies it gets assigned to it
                //it needs to know that its part of this DCA
                SerializedProperty thisPreloadWardrobeRecipes = serializedObject.FindProperty("preloadWardrobeRecipes");
                Rect pwrCurrentRect = EditorGUILayout.GetControlRect(false, _wardrobePropDrawer.GetPropertyHeight(thisPreloadWardrobeRecipes, GUIContent.none));
                _wardrobePropDrawer.OnGUI(pwrCurrentRect, thisPreloadWardrobeRecipes, new GUIContent(thisPreloadWardrobeRecipes.displayName));
                if (showHelp)
                {
                    EditorGUILayout.HelpBox("Preload Wardrobe: Sets the default wardrobe recipes to use on the Avatar. This is useful when creating specific Avatar prefabs.", MessageType.Info);
                }
                if (_wardrobePropDrawer.changed)
                {
                    serializedObject.ApplyModifiedProperties();
                    if (Application.isPlaying)
                    {
                        thisDCA.ClearSlots();
                        thisDCA.LoadDefaultWardrobe();
                        thisDCA.BuildCharacter(true);
                    }
                    else
                    {
                        GenerateSingleUMA();
                    }
                }
                // *********************************************************************************
                //
                //NewCharacterColors
                SerializedProperty characterColors    = serializedObject.FindProperty("characterColors");
                SerializedProperty newCharacterColors = characterColors.FindPropertyRelative("_colors");
                GUILayout.BeginHorizontal();
                GUILayout.Space(2);
                //for ColorValues as OverlayColorDatas we need to outout something that looks like a list but actully uses a method to add/remove colors because we need the new OverlayColorData to have 3 channels
                newCharacterColors.isExpanded = EditorGUILayout.Foldout(newCharacterColors.isExpanded, new GUIContent("Character Colors"));
                GUILayout.EndHorizontal();
                var n_origArraySize = newCharacterColors.arraySize;
                var n_newArraySize  = n_origArraySize;
                EditorGUI.BeginChangeCheck();
                if (newCharacterColors.isExpanded)
                {
                    currentcolorfilter = EditorGUILayout.Popup("Filter Colors", currentcolorfilter, colorfilters);

                    n_newArraySize = EditorGUILayout.DelayedIntField(new GUIContent("Size"), n_origArraySize);
                    EditorGUILayout.Space();
                    EditorGUI.indentLevel++;
                    if (n_origArraySize > 0)
                    {
                        for (int i = 0; i < n_origArraySize; i++)
                        {
                            SerializedProperty currentColor = newCharacterColors.GetArrayElementAtIndex(i);
                            if (currentcolorfilter == 0 && !baseColorNames.Contains(currentColor.displayName.ToLower()))
                            {
                                continue;
                            }
                            if (currentcolorfilter == 2 && currentColor.displayName.ToLower().Contains("colordna"))
                            {
                                continue;
                            }
                            EditorGUILayout.PropertyField(newCharacterColors.GetArrayElementAtIndex(i));
                        }
                    }
                    EditorGUI.indentLevel--;
                }
                if (showHelp)
                {
                    EditorGUILayout.HelpBox("Character Colors: This lets you set predefined colors to be used when building the Avatar. The colors will be assigned to the Shared Colors on the overlays as they are applied to the Avatar.", MessageType.Info);
                }
                if (EditorGUI.EndChangeCheck())
                {
                    if (n_newArraySize != n_origArraySize)
                    {
                        SetNewColorCount(n_newArraySize);                        //this is not prompting a save so mark the scene dirty...
                        if (!Application.isPlaying)
                        {
                            EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
                        }
                    }
                    serializedObject.ApplyModifiedProperties();
                    if (Application.isPlaying)
                    {
                        thisDCA.UpdateColors(true);
                    }
                    else
                    {
                        GenerateSingleUMA();
                        //thisDCA.UpdateColors(false); // todo: this block is losing all the colors in the recipe somehow...
                        //thisDCA.umaData.isTextureDirty = true;
                        //UpdateUMA();
                    }
                }

                //***********************************************************************************
                // Predefined DNA
                //***********************************************************************************

                // Dropdown of the current DNA.
                // button to "add" it.

                showPrefinedDNA = EditorGUILayout.Foldout(showPrefinedDNA, "Predefined DNA");
                if (showPrefinedDNA)
                {
                    if (cachedRace != thisDCA.activeRace.name)
                    {
                        cachedRace       = thisDCA.activeRace.name;
                        rawcachedRaceDNA = thisDCA.activeRace.data.GetDNANames().ToArray();
                        List <string> MenuDNA = new List <string>();
                        foreach (string s in rawcachedRaceDNA)
                        {
                            MenuDNA.Add(s.MenuCamelCase());
                        }
                        cachedRaceDNA = MenuDNA.ToArray();
                    }

                    GUILayout.BeginHorizontal();
                    currentDNA = EditorGUILayout.Popup(currentDNA, cachedRaceDNA);
                    if (GUILayout.Button("Add DNA"))
                    {
                        string theDna = rawcachedRaceDNA[currentDNA];

                        if (thisDCA.predefinedDNA == null)
                        {
                            thisDCA.predefinedDNA = new UMAPredefinedDNA();
                        }
                        if (thisDCA.predefinedDNA.ContainsName(theDna))
                        {
                            EditorUtility.DisplayDialog("Error", "Predefined DNA Already contains DNA: " + theDna, "OK");
                        }
                        else
                        {
                            AddSingleDNA(theDna);
                        }
                    }
                    if (GUILayout.Button("Add All"))
                    {
                        foreach (string s in rawcachedRaceDNA)
                        {
                            if (!thisDCA.predefinedDNA.ContainsName(s))
                            {
                                AddSingleDNA(s);
                            }
                        }
                    }
                    GUILayout.EndHorizontal();

                    if (thisDCA.predefinedDNA != null)
                    {
                        string delme = "";
                        EditorGUI.BeginChangeCheck();
                        foreach (var pd in thisDCA.predefinedDNA.PreloadValues)
                        {
                            GUILayout.BeginHorizontal();
                            GUILayout.Label(ObjectNames.NicifyVariableName(pd.Name), GUILayout.Width(100));
                            pd.Value = GUILayout.HorizontalSlider(pd.Value, 0.0f, 1.0f);

                            bool delete = GUILayout.Button("\u0078", EditorStyles.miniButton, GUILayout.ExpandWidth(false));
                            if (delete)
                            {
                                delme = pd.Name;
                            }
                            GUILayout.EndHorizontal();
                        }
                        if (!string.IsNullOrEmpty(delme))
                        {
                            thisDCA.predefinedDNA.RemoveDNA(delme);
                            GenerateSingleUMA();
                            Repaint();
                        }
                        if (EditorGUI.EndChangeCheck())
                        {
                            GenerateSingleUMA();
                        }
                    }
                }
                if (showHelp)
                {
                    EditorGUILayout.HelpBox("Predefined DNA is loaded onto the character in the initial character build. Select the DNA in the dropdown, and add it to the list of DNA to load, then edit the values as needed.", MessageType.Info);
                }
                EndVerticalPadded();
            }

            //**************************************
            // End In-Editor customization
            //**************************************


            //the ChangeRaceOptions
            SerializedProperty defaultChangeRaceOptions = serializedObject.FindProperty("defaultChangeRaceOptions");

            defaultChangeRaceOptions.isExpanded = EditorGUILayout.Foldout(defaultChangeRaceOptions.isExpanded, new GUIContent("Race Change Options", "The default options for when the Race is changed. These can be overidden when calling 'ChangeRace' directly."));
            if (defaultChangeRaceOptions.isExpanded)
            {
                BeginVerticalPadded();
                EditorGUI.BeginChangeCheck();
                EditorGUILayout.PropertyField(defaultChangeRaceOptions, GUIContent.none);
                EditorGUI.indentLevel++;
                EditorGUILayout.PropertyField(serializedObject.FindProperty("cacheCurrentState"));
                EditorGUILayout.PropertyField(serializedObject.FindProperty("rebuildSkeleton"));
                EditorGUI.indentLevel--;
                if (EditorGUI.EndChangeCheck())
                {
                    serializedObject.ApplyModifiedProperties();
                }
                EndVerticalPadded();
            }


            //Move UMAAddidtionalRecipes out of advanced into its own section
            EditorGUI.BeginChangeCheck();
            EditorGUILayout.PropertyField(umaAdditionalRecipes, new GUIContent("Additional Utility Recipes", "Additional Recipes to add when the character is generated, like the capsuleCollider recipe for example"), true);
            if (EditorGUI.EndChangeCheck())
            {
                serializedObject.ApplyModifiedProperties();
            }
            GUILayout.Space(2f);

            SerializedProperty thisRaceAnimationControllers = serializedObject.FindProperty("raceAnimationControllers");
            Rect racCurrentRect = EditorGUILayout.GetControlRect(false, _animatorPropDrawer.GetPropertyHeight(thisRaceAnimationControllers, GUIContent.none));

            EditorGUI.BeginChangeCheck();
            _animatorPropDrawer.OnGUI(racCurrentRect, thisRaceAnimationControllers, new GUIContent(thisRaceAnimationControllers.displayName));
            if (showHelp)
            {
                EditorGUILayout.HelpBox("Race Animation Controllers: This sets the animation controllers used for each race. When changing the race, the animation controller for the active race will be used by default.", MessageType.Info);
            }
            //EditorGUI.BeginChangeCheck();
            //EditorGUILayout.PropertyField(serializedObject.FindProperty("raceAnimationControllers"));
            if (EditorGUI.EndChangeCheck())
            {
                serializedObject.ApplyModifiedProperties();
                if (Application.isPlaying)
                {
                    thisDCA.SetExpressionSet();                    //this triggers any expressions to reset.
                    thisDCA.SetAnimatorController();
                }
            }

            GUILayout.Space(2f);
            //Load save fields
            EditorGUI.BeginChangeCheck();
            SerializedProperty loadPathType = serializedObject.FindProperty("loadPathType");

            loadPathType.isExpanded = EditorGUILayout.Foldout(loadPathType.isExpanded, "Load/Save Options");
            if (loadPathType.isExpanded)
            {
                SerializedProperty loadString      = serializedObject.FindProperty("loadString");
                SerializedProperty loadPath        = serializedObject.FindProperty("loadPath");
                SerializedProperty loadFilename    = serializedObject.FindProperty("loadFilename");
                SerializedProperty loadFileOnStart = serializedObject.FindProperty("loadFileOnStart");
                SerializedProperty savePathType    = serializedObject.FindProperty("savePathType");
                SerializedProperty savePath        = serializedObject.FindProperty("savePath");
                SerializedProperty saveFilename    = serializedObject.FindProperty("saveFilename");
                //LoadSave Flags
                SerializedProperty defaultLoadOptions = serializedObject.FindProperty("defaultLoadOptions");
                SerializedProperty defaultSaveOptions = serializedObject.FindProperty("defaultSaveOptions");
                //extra LoadSave Options in addition to flags
                //SerializedProperty waitForBundles = serializedObject.FindProperty("waitForBundles");
                SerializedProperty makeUniqueFilename = serializedObject.FindProperty("makeUniqueFilename");
                SerializedProperty ensureSharedColors = serializedObject.FindProperty("ensureSharedColors");

                EditorGUILayout.PropertyField(loadPathType);

                if (loadPathType.enumValueIndex == Convert.ToInt32(DynamicCharacterAvatar.loadPathTypes.String))
                {
                    EditorGUILayout.PropertyField(loadString);
                }
                else
                {
                    if (loadPathType.enumValueIndex <= 1)
                    {
                        EditorGUILayout.PropertyField(loadPath);
                    }
                }

                EditorGUILayout.PropertyField(loadFilename);
                if (loadFilename.stringValue != "")
                {
                    EditorGUILayout.PropertyField(loadFileOnStart);
                }
                EditorGUI.indentLevel++;
                //LoadOptionsFlags
                defaultLoadOptions.isExpanded = EditorGUILayout.Foldout(defaultLoadOptions.isExpanded, new GUIContent("Load Options", "The default options for when a character is loaded from an UMATextRecipe asset or a recipe string. Can be overidden when calling 'LoadFromRecipe' or 'LoadFromString' directly."));
                if (defaultLoadOptions.isExpanded)
                {
                    EditorGUILayout.PropertyField(defaultLoadOptions, GUIContent.none);
                    EditorGUI.indentLevel++;
                    //waitForBundles.boolValue = EditorGUILayout.ToggleLeft(new GUIContent(waitForBundles.displayName, waitForBundles.tooltip), waitForBundles.boolValue);
                    //buildAfterLoad.boolValue = EditorGUILayout.ToggleLeft(new GUIContent(buildAfterLoad.displayName, buildAfterLoad.tooltip), buildAfterLoad.boolValue);
                    //just drawing these as propertyFields because the toolTip on toggle left doesn't work
                    //EditorGUILayout.PropertyField(waitForBundles);
                    EditorGUI.indentLevel--;
                }
                EditorGUI.indentLevel--;
                if (Application.isPlaying)
                {
                    if (GUILayout.Button("Perform Load"))
                    {
                        thisDCA.DoLoad();
                    }
                }
                EditorGUILayout.Space();
                EditorGUILayout.PropertyField(savePathType);
                if (savePathType.enumValueIndex <= 2)
                {
                    EditorGUILayout.PropertyField(savePath);
                }
                EditorGUILayout.PropertyField(saveFilename);
                EditorGUI.indentLevel++;
                defaultSaveOptions.isExpanded = EditorGUILayout.Foldout(defaultSaveOptions.isExpanded, new GUIContent("Save Options", "The default options for when a character is save to UMATextRecipe asset or a txt. Can be overidden when calling 'DoSave' directly."));
                if (defaultSaveOptions.isExpanded)
                {
                    EditorGUILayout.PropertyField(defaultSaveOptions, GUIContent.none);
                    EditorGUI.indentLevel++;
                    //ensureSharedColors.boolValue = EditorGUILayout.ToggleLeft(new GUIContent(ensureSharedColors.displayName, ensureSharedColors.tooltip), ensureSharedColors.boolValue);
                    //makeUniqueFilename.boolValue = EditorGUILayout.ToggleLeft(new GUIContent(makeUniqueFilename.displayName, makeUniqueFilename.tooltip), makeUniqueFilename.boolValue);
                    //just drawing these as propertyFields because the toolTip on toggle left doesn't work
                    EditorGUILayout.PropertyField(ensureSharedColors);
                    EditorGUILayout.PropertyField(makeUniqueFilename);
                    EditorGUI.indentLevel--;
                }
                EditorGUI.indentLevel--;
                if (Application.isPlaying)
                {
                    if (GUILayout.Button("Perform Save"))
                    {
                        thisDCA.DoSave();
                    }
                }
                EditorGUILayout.Space();
            }
            if (EditorGUI.EndChangeCheck())
            {
                serializedObject.ApplyModifiedProperties();
            }
            GUILayout.Space(2f);
            //for CharacterEvents
            EditorGUI.BeginChangeCheck();
            SerializedProperty CharacterCreated = serializedObject.FindProperty("CharacterCreated");

            CharacterCreated.isExpanded = EditorGUILayout.Foldout(CharacterCreated.isExpanded, "Character Events");
            if (CharacterCreated.isExpanded)
            {
                SerializedProperty CharacterBegun      = serializedObject.FindProperty("CharacterBegun");
                SerializedProperty CharacterUpdated    = serializedObject.FindProperty("CharacterUpdated");
                SerializedProperty CharacterDestroyed  = serializedObject.FindProperty("CharacterDestroyed");
                SerializedProperty CharacterDnaUpdated = serializedObject.FindProperty("CharacterDnaUpdated");
                SerializedProperty RecipeUpdated       = serializedObject.FindProperty("RecipeUpdated");
                SerializedProperty AnimatorSaved       = serializedObject.FindProperty("AnimatorStateSaved");
                SerializedProperty AnimatorRestored    = serializedObject.FindProperty("AnimatorStateRestored");
                SerializedProperty WardrobeAdded       = serializedObject.FindProperty("WardrobeAdded");
                SerializedProperty WardrobeRemoved     = serializedObject.FindProperty("WardrobeRemoved");

                EditorGUILayout.PropertyField(CharacterBegun);
                EditorGUILayout.PropertyField(CharacterCreated);
                EditorGUILayout.PropertyField(CharacterUpdated);
                EditorGUILayout.PropertyField(CharacterDestroyed);
                EditorGUILayout.PropertyField(CharacterDnaUpdated);
                EditorGUILayout.PropertyField(RecipeUpdated);
                EditorGUILayout.PropertyField(AnimatorSaved);
                EditorGUILayout.PropertyField(AnimatorRestored);
                EditorGUILayout.PropertyField(WardrobeAdded);
                EditorGUILayout.PropertyField(WardrobeRemoved);
            }
            if (EditorGUI.EndChangeCheck())
            {
                serializedObject.ApplyModifiedProperties();
            }
            GUILayout.Space(2f);
            //for AdvancedOptions
            EditorGUI.BeginChangeCheck();
            context.isExpanded = EditorGUILayout.Foldout(context.isExpanded, "Advanced Options");
            if (context.isExpanded)
            {
                EditorGUI.BeginChangeCheck();
                EditorGUILayout.PropertyField(serializedObject.FindProperty("alwaysRebuildSkeleton"));
                EditorGUILayout.PropertyField(serializedObject.FindProperty("hide"));
                EditorGUILayout.PropertyField(serializedObject.FindProperty("DelayUnload"));
                EditorGUILayout.PropertyField(serializedObject.FindProperty("BundleCheck"));
                EditorGUILayout.PropertyField(serializedObject.FindProperty("AtlasResolutionScale"));
                EditorGUILayout.PropertyField(serializedObject.FindProperty("defaultRendererAsset"));

                if (EditorGUI.EndChangeCheck())
                {
                    serializedObject.ApplyModifiedProperties();
                }
                if (showHelp)
                {
                    EditorGUILayout.HelpBox("Hide: This disables the display of the Avatar without preventing it from being generated. If you want to prevent the character from being generated at all disable the DynamicCharacterAvatar component itself.", MessageType.Info);
                }
                //for _buildCharacterEnabled we want to set the value using the DCS BuildCharacterEnabled property because this actually triggers BuildCharacter
                var buildCharacterEnabled      = serializedObject.FindProperty("_buildCharacterEnabled");
                var buildCharacterEnabledValue = buildCharacterEnabled.boolValue;
                EditorGUI.BeginChangeCheck();
                var buildCharacterEnabledNewValue = EditorGUILayout.Toggle(new GUIContent(buildCharacterEnabled.displayName, "Builds the character on recipe load or race changed. If you want to load multiple recipes into a character you can disable this and enable it when you are done. By default this should be true."), buildCharacterEnabledValue);
                if (EditorGUI.EndChangeCheck())
                {
                    if (buildCharacterEnabledNewValue != buildCharacterEnabledValue)
                    {
                        thisDCA.BuildCharacterEnabled = buildCharacterEnabledNewValue;
                    }
                    serializedObject.ApplyModifiedProperties();
                }
                if (showHelp)
                {
                    EditorGUILayout.HelpBox("Build Character Enabled: Builds the character on recipe load or race changed. If you want to load multiple recipes into a character you can disable this and enable it when you are done. By default this should be true.", MessageType.Info);
                }
                EditorGUILayout.PropertyField(serializedObject.FindProperty("loadBlendShapes"), new GUIContent("Load BlendShapes"));
                EditorGUILayout.PropertyField(serializedObject.FindProperty("keepAvatar"), new GUIContent("Keep Avatar"));
                EditorGUILayout.PropertyField(serializedObject.FindProperty("KeepAnimatorController"), new GUIContent("Keep Animator Controller"));
                EditorGUILayout.PropertyField(context);
                EditorGUILayout.PropertyField(umaData);
                EditorGUILayout.PropertyField(umaGenerator);
                EditorGUILayout.Space();
//				EditorGUILayout.PropertyField(umaRecipe);
                EditorGUILayout.PropertyField(animationController);
                EditorGUILayout.PropertyField(serializedObject.FindProperty("BoundsOffset"));
            }
            if (EditorGUI.EndChangeCheck())
            {
                serializedObject.ApplyModifiedProperties();
            }
            GUILayout.Space(2f);
            //for PlaceholderOptions
            EditorGUI.BeginChangeCheck();
            SerializedProperty gizmo          = serializedObject.FindProperty("showPlaceholder");
            SerializedProperty enableGizmo    = serializedObject.FindProperty("showPlaceholder");
            SerializedProperty previewModel   = serializedObject.FindProperty("previewModel");
            SerializedProperty customModel    = serializedObject.FindProperty("customModel");
            SerializedProperty customRotation = serializedObject.FindProperty("customRotation");
            SerializedProperty previewColor   = serializedObject.FindProperty("previewColor");

            gizmo.isExpanded = EditorGUILayout.Foldout(gizmo.isExpanded, "Placeholder Options");
            if (gizmo.isExpanded)
            {
                EditorGUILayout.PropertyField(enableGizmo);
                EditorGUILayout.PropertyField(previewModel);
                if (previewModel.enumValueIndex == 2)
                {
                    EditorGUILayout.PropertyField(customModel);
                    EditorGUILayout.PropertyField(customRotation);
                }
                EditorGUILayout.PropertyField(previewColor);
            }
            if (EditorGUI.EndChangeCheck())
            {
                serializedObject.ApplyModifiedProperties();
            }

            if (Application.isPlaying)
            {
                showWardrobe = EditorGUILayout.Foldout(showWardrobe, "Current Wardrobe");
                if (showWardrobe)
                {
                    EditorGUI.indentLevel++;
                    Dictionary <string, UMATextRecipe> currentWardrobe = thisDCA.WardrobeRecipes;

                    foreach (KeyValuePair <string, UMATextRecipe> item in currentWardrobe)
                    {
                        GUILayout.BeginHorizontal();
                        EditorGUI.BeginDisabledGroup(true);
                        EditorGUILayout.LabelField(item.Key, GUILayout.Width(88.0f));
                        EditorGUILayout.TextField(item.Value.DisplayValue + " (" + item.Value.name + ")");
                        EditorGUI.EndDisabledGroup();
                        if (GUILayout.Button("Inspect", EditorStyles.toolbarButton, GUILayout.Width(40)))
                        {
                            InspectorUtlity.InspectTarget(item.Value);
                        }
                        GUILayout.EndHorizontal();
                    }
                    EditorGUI.indentLevel--;
                }
            }

            List <GameObject> GetRenderers(GameObject parent)
            {
                List <GameObject> objs = new List <GameObject>();

                foreach (Transform t in parent.transform)
                {
                    if (t.GetComponent <SkinnedMeshRenderer>() != null)
                    {
                        objs.Add(t.gameObject);
                    }
                }
                return(objs);
            }

            /* void UpdateUMA()
             * {
             *      UMAGenerator ugb = UMAContext.Instance.gameObject.GetComponentInChildren<UMAGenerator>();
             *      if (ugb == null)
             *      {
             *              EditorUtility.DisplayDialog("Error", "Cannot find generator!", "OK");
             *      }
             *      else
             *      {
             *              DynamicCharacterAvatar dca = target as DynamicCharacterAvatar;
             *              bool oldFastGen = ugb.fastGeneration;
             *              ugb.fastGeneration = true;
             *              ugb.FreezeTime = true;
             *              ugb.GenerateSingleUMA(dca.umaData);
             *              ugb.fastGeneration = oldFastGen;
             *              ugb.FreezeTime = false;
             *      }
             * } */

            void GenerateSingleUMA()
            {
                if (Application.isPlaying)
                {
                    return;
                }

                if (thisDCA.editorTimeGeneration == false)
                {
                    return;
                }

                // Debug.Log("prefab instance asset type: " + PrefabUtility.GetPrefabInstanceStatus(thisDCA.gameObject) + ", asset type: " + PrefabUtility.GetPrefabAssetType(thisDCA.gameObject));

                // Don't generate UMAs from project prefabs or if the gameObject is not active.
                if (!thisDCA.gameObject.activeInHierarchy)                //PrefabUtility.GetPrefabInstanceStatus(thisDCA.gameObject) == PrefabInstanceStatus.NotAPrefab && PrefabUtility.GetPrefabAssetType(thisDCA.gameObject) != PrefabAssetType.NotAPrefab)
                {
                    return;
                }

                UMAGenerator ugb = UMAContext.Instance.gameObject.GetComponentInChildren <UMAGenerator>();

                if (ugb == null)
                {
                    EditorUtility.DisplayDialog("Error", "Cannot find generator!", "OK");
                }
                else
                {
                    DynamicCharacterAvatar dca = target as DynamicCharacterAvatar;

                    CleanupGeneratedData();

                    dca.activeRace.SetRaceData();
                    if (dca.activeRace.racedata == null)
                    {
                        return;
                    }

                    dca.LoadDefaultWardrobe();

                    // save the predefined DNA...
                    var dna = dca.predefinedDNA.Clone();
                    dca.BuildCharacter(false, true);
                    dca.predefinedDNA = dna;

                    bool oldFastGen         = ugb.fastGeneration;
                    int  oldScaleFactor     = ugb.InitialScaleFactor;
                    int  oldAtlasResolution = ugb.atlasResolution;

                    ugb.FreezeTime         = true;
                    ugb.fastGeneration     = true;
                    ugb.InitialScaleFactor = ugb.editorInitialScaleFactor;
                    ugb.atlasResolution    = ugb.editorAtlasResolution;


                    dca.activeRace.racedata.ResetDNA();

                    ugb.GenerateSingleUMA(dca.umaData, false);

                    ugb.fastGeneration     = oldFastGen;
                    ugb.FreezeTime         = false;
                    ugb.InitialScaleFactor = oldScaleFactor;
                    ugb.atlasResolution    = oldAtlasResolution;

                    var mountedItems = dca.gameObject.GetComponentsInChildren <UMAMountedItem>();
                    foreach (var mi in mountedItems)
                    {
                        mi.ResetMountPoint();
                    }
                }
            }

            void CleanupGeneratedData()
            {
                if (Application.isPlaying)
                {
                    return;
                }
                List <GameObject> Cleaners = GetRenderers(thisDCA.gameObject);

                thisDCA.Hide();
                foreach (GameObject go in Cleaners)
                {
                    DestroyImmediate(go);
                }
                DestroyImmediate(thisDCA.umaData);
                thisDCA.umaData = null;
                thisDCA.ClearSlots();
            }

            void UpdateCharacter()
            {
                if (thisDCA.gameObject.scene != default)
                {
                    if (thisDCA.editorTimeGeneration)
                    {
                        GenerateSingleUMA();
                    }
                    else
                    {
                        CleanupGeneratedData();
                    }
                }
            }
        }
        public override void OnInspectorGUI()
        {
            serializedObject.Update();
            Editor.DrawPropertiesExcluding(serializedObject, new string[] { "hide", "BundleCheck", "loadBlendShapes", "activeRace", "defaultChangeRaceOptions", "cacheCurrentState", "rebuildSkeleton", "preloadWardrobeRecipes", "raceAnimationControllers",
                                                                            "characterColors", "BoundsOffset", "_buildCharacterEnabled", "keepAvatar", "KeepAnimatorController",
                                                                            /*LoadOtions fields*/ "defaultLoadOptions", "loadPathType", "loadPath", "loadFilename", "loadString", "loadFileOnStart", "waitForBundles", /*"buildAfterLoad",*/
                                                                            /*SaveOptions fields*/ "defaultSaveOptions", "savePathType", "savePath", "saveFilename", "makeUniqueFilename", "ensureSharedColors",
                                                                            /*Moved into AdvancedOptions*/ "context", "umaData", "umaRecipe", "umaAdditionalRecipes", "umaGenerator", "animationController", "defaultRendererAsset",
                                                                            /*Moved into CharacterEvents*/ "CharacterCreated", "CharacterBegun", "CharacterUpdated", "CharacterDestroyed", "CharacterDnaUpdated", "RecipeUpdated", "AnimatorStateSaved", "AnimatorStateRestored",
                                                                            /*PlaceholderOptions fields*/ "showPlaceholder", "previewModel", "customModel", "customRotation", "previewColor", "AtlasResolutionScale" });

            //The base DynamicAvatar properties- get these early because changing the race changes someof them
            SerializedProperty context              = serializedObject.FindProperty("context");
            SerializedProperty umaData              = serializedObject.FindProperty("umaData");
            SerializedProperty umaGenerator         = serializedObject.FindProperty("umaGenerator");
            SerializedProperty umaRecipe            = serializedObject.FindProperty("umaRecipe");
            SerializedProperty umaAdditionalRecipes = serializedObject.FindProperty("umaAdditionalRecipes");
            SerializedProperty animationController  = serializedObject.FindProperty("animationController");

            EditorGUI.BeginChangeCheck();
            EditorGUILayout.PropertyField(serializedObject.FindProperty("BundleCheck"));
            if (EditorGUI.EndChangeCheck())
            {
                serializedObject.ApplyModifiedProperties();
            }

            EditorGUI.BeginChangeCheck();
            showHelp = EditorGUILayout.Toggle("Show Help", showHelp);
            if (EditorGUI.EndChangeCheck())
            {
                serializedObject.ApplyModifiedProperties();
            }
            SerializedProperty thisRaceSetter = serializedObject.FindProperty("activeRace");
            Rect currentRect = EditorGUILayout.GetControlRect(false, _racePropDrawer.GetPropertyHeight(thisRaceSetter, GUIContent.none));

            EditorGUI.BeginChangeCheck();
            _racePropDrawer.OnGUI(currentRect, thisRaceSetter, new GUIContent(thisRaceSetter.displayName));
            if (EditorGUI.EndChangeCheck())
            {
                thisDCA.ChangeRace((string)thisRaceSetter.FindPropertyRelative("name").stringValue);
                //Changing the race may cause umaRecipe, animationController to change so forcefully update these too
                umaRecipe.objectReferenceValue           = thisDCA.umaRecipe;
                animationController.objectReferenceValue = thisDCA.animationController;
                serializedObject.ApplyModifiedProperties();
            }
            if (showHelp)
            {
                EditorGUILayout.HelpBox("Active Race: Sets the race of the character, which defines the base recipe to build the character, the available DNA, and the available wardrobe.", MessageType.Info);
            }
            //the ChangeRaceOptions
            SerializedProperty defaultChangeRaceOptions = serializedObject.FindProperty("defaultChangeRaceOptions");

            EditorGUI.indentLevel++;
            defaultChangeRaceOptions.isExpanded = EditorGUILayout.Foldout(defaultChangeRaceOptions.isExpanded, new GUIContent("Race Change Options", "The default options for when the Race is changed. These can be overidden when calling 'ChangeRace' directly."));
            if (defaultChangeRaceOptions.isExpanded)
            {
                EditorGUI.BeginChangeCheck();
                EditorGUILayout.PropertyField(defaultChangeRaceOptions, GUIContent.none);
                EditorGUI.indentLevel++;
                EditorGUILayout.PropertyField(serializedObject.FindProperty("cacheCurrentState"));
                EditorGUILayout.PropertyField(serializedObject.FindProperty("rebuildSkeleton"));
                EditorGUI.indentLevel--;
                if (EditorGUI.EndChangeCheck())
                {
                    serializedObject.ApplyModifiedProperties();
                }
            }
            EditorGUI.indentLevel--;
            //Other DCA propertyDrawers
            //in order for the "preloadWardrobeRecipes" prop to properly check if it can load the recipies it gets assigned to it
            //it needs to know that its part of this DCA
            GUILayout.Space(2f);
            SerializedProperty thisPreloadWardrobeRecipes = serializedObject.FindProperty("preloadWardrobeRecipes");
            Rect pwrCurrentRect = EditorGUILayout.GetControlRect(false, _wardrobePropDrawer.GetPropertyHeight(thisPreloadWardrobeRecipes, GUIContent.none));

            _wardrobePropDrawer.OnGUI(pwrCurrentRect, thisPreloadWardrobeRecipes, new GUIContent(thisPreloadWardrobeRecipes.displayName));
            if (showHelp)
            {
                EditorGUILayout.HelpBox("Preload Wardrobe: Sets the default wardrobe recipes to use on the Avatar. This is useful when creating specific Avatar prefabs.", MessageType.Info);
            }
            if (_wardrobePropDrawer.changed)
            {
                serializedObject.ApplyModifiedProperties();
                if (Application.isPlaying)
                {
                    thisDCA.ClearSlots();
                    thisDCA.LoadDefaultWardrobe();
                    thisDCA.BuildCharacter(true);
                }
            }

            //Move UMAAddidtionalRecipes out of advanced into its own section
            EditorGUI.BeginChangeCheck();
            EditorGUILayout.PropertyField(umaAdditionalRecipes, new GUIContent("Additional Utility Recipes", "Additional Recipes to add when the character is generated, like the capsuleCollider recipe for example"), true);
            if (EditorGUI.EndChangeCheck())
            {
                serializedObject.ApplyModifiedProperties();
            }
            GUILayout.Space(2f);

            SerializedProperty thisRaceAnimationControllers = serializedObject.FindProperty("raceAnimationControllers");
            Rect racCurrentRect = EditorGUILayout.GetControlRect(false, _animatorPropDrawer.GetPropertyHeight(thisRaceAnimationControllers, GUIContent.none));

            EditorGUI.BeginChangeCheck();
            _animatorPropDrawer.OnGUI(racCurrentRect, thisRaceAnimationControllers, new GUIContent(thisRaceAnimationControllers.displayName));
            if (showHelp)
            {
                EditorGUILayout.HelpBox("Race Animation Controllers: This sets the animation controllers used for each race. When changing the race, the animation controller for the active race will be used by default.", MessageType.Info);
            }
            //EditorGUI.BeginChangeCheck();
            //EditorGUILayout.PropertyField(serializedObject.FindProperty("raceAnimationControllers"));
            if (EditorGUI.EndChangeCheck())
            {
                serializedObject.ApplyModifiedProperties();
                if (Application.isPlaying)
                {
                    thisDCA.SetExpressionSet();                    //this triggers any expressions to reset.
                    thisDCA.SetAnimatorController();
                }
            }
            //NewCharacterColors
            SerializedProperty characterColors    = serializedObject.FindProperty("characterColors");
            SerializedProperty newCharacterColors = characterColors.FindPropertyRelative("_colors");

            //for ColorValues as OverlayColorDatas we need to outout something that looks like a list but actully uses a method to add/remove colors because we need the new OverlayColorData to have 3 channels
            newCharacterColors.isExpanded = EditorGUILayout.Foldout(newCharacterColors.isExpanded, new GUIContent("Character Colors"));
            var n_origArraySize = newCharacterColors.arraySize;
            var n_newArraySize  = n_origArraySize;

            EditorGUI.BeginChangeCheck();
            if (newCharacterColors.isExpanded)
            {
                n_newArraySize = EditorGUILayout.DelayedIntField(new GUIContent("Size"), n_origArraySize);
                EditorGUILayout.Space();
                EditorGUI.indentLevel++;
                if (n_origArraySize > 0)
                {
                    for (int i = 0; i < n_origArraySize; i++)
                    {
                        EditorGUILayout.PropertyField(newCharacterColors.GetArrayElementAtIndex(i));
                    }
                }
                EditorGUI.indentLevel--;
            }
            if (showHelp)
            {
                EditorGUILayout.HelpBox("Character Colors: This lets you set predefined colors to be used when building the Avatar. The colors will be assigned to the Shared Colors on the overlays as they are applied to the Avatar.", MessageType.Info);
            }
            if (EditorGUI.EndChangeCheck())
            {
                if (n_newArraySize != n_origArraySize)
                {
                    SetNewColorCount(n_newArraySize);                    //this is not prompting a save so mark the scene dirty...
                    if (!Application.isPlaying)
                    {
                        EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
                    }
                }
                serializedObject.ApplyModifiedProperties();
                if (Application.isPlaying)
                {
                    thisDCA.UpdateColors(true);
                }
            }
            GUILayout.Space(2f);
            //Load save fields
            EditorGUI.BeginChangeCheck();
            SerializedProperty loadPathType = serializedObject.FindProperty("loadPathType");

            loadPathType.isExpanded = EditorGUILayout.Foldout(loadPathType.isExpanded, "Load/Save Options");
            if (loadPathType.isExpanded)
            {
                SerializedProperty loadString      = serializedObject.FindProperty("loadString");
                SerializedProperty loadPath        = serializedObject.FindProperty("loadPath");
                SerializedProperty loadFilename    = serializedObject.FindProperty("loadFilename");
                SerializedProperty loadFileOnStart = serializedObject.FindProperty("loadFileOnStart");
                SerializedProperty savePathType    = serializedObject.FindProperty("savePathType");
                SerializedProperty savePath        = serializedObject.FindProperty("savePath");
                SerializedProperty saveFilename    = serializedObject.FindProperty("saveFilename");
                //LoadSave Flags
                SerializedProperty defaultLoadOptions = serializedObject.FindProperty("defaultLoadOptions");
                SerializedProperty defaultSaveOptions = serializedObject.FindProperty("defaultSaveOptions");
                //extra LoadSave Options in addition to flags
                //SerializedProperty waitForBundles = serializedObject.FindProperty("waitForBundles");
                SerializedProperty makeUniqueFilename = serializedObject.FindProperty("makeUniqueFilename");
                SerializedProperty ensureSharedColors = serializedObject.FindProperty("ensureSharedColors");

                EditorGUILayout.PropertyField(loadPathType);

                if (loadPathType.enumValueIndex == Convert.ToInt32(DynamicCharacterAvatar.loadPathTypes.String))
                {
                    EditorGUILayout.PropertyField(loadString);
                }
                else
                {
                    if (loadPathType.enumValueIndex <= 1)
                    {
                        EditorGUILayout.PropertyField(loadPath);
                    }
                }

                EditorGUILayout.PropertyField(loadFilename);
                if (loadFilename.stringValue != "")
                {
                    EditorGUILayout.PropertyField(loadFileOnStart);
                }
                EditorGUI.indentLevel++;
                //LoadOptionsFlags
                defaultLoadOptions.isExpanded = EditorGUILayout.Foldout(defaultLoadOptions.isExpanded, new GUIContent("Load Options", "The default options for when a character is loaded from an UMATextRecipe asset or a recipe string. Can be overidden when calling 'LoadFromRecipe' or 'LoadFromString' directly."));
                if (defaultLoadOptions.isExpanded)
                {
                    EditorGUILayout.PropertyField(defaultLoadOptions, GUIContent.none);
                    EditorGUI.indentLevel++;
                    //waitForBundles.boolValue = EditorGUILayout.ToggleLeft(new GUIContent(waitForBundles.displayName, waitForBundles.tooltip), waitForBundles.boolValue);
                    //buildAfterLoad.boolValue = EditorGUILayout.ToggleLeft(new GUIContent(buildAfterLoad.displayName, buildAfterLoad.tooltip), buildAfterLoad.boolValue);
                    //just drawing these as propertyFields because the toolTip on toggle left doesn't work
                    //EditorGUILayout.PropertyField(waitForBundles);
                    EditorGUI.indentLevel--;
                }
                EditorGUI.indentLevel--;
                if (Application.isPlaying)
                {
                    if (GUILayout.Button("Perform Load"))
                    {
                        thisDCA.DoLoad();
                    }
                }
                EditorGUILayout.Space();
                EditorGUILayout.PropertyField(savePathType);
                if (savePathType.enumValueIndex <= 2)
                {
                    EditorGUILayout.PropertyField(savePath);
                }
                EditorGUILayout.PropertyField(saveFilename);
                EditorGUI.indentLevel++;
                defaultSaveOptions.isExpanded = EditorGUILayout.Foldout(defaultSaveOptions.isExpanded, new GUIContent("Save Options", "The default options for when a character is save to UMATextRecipe asset or a txt. Can be overidden when calling 'DoSave' directly."));
                if (defaultSaveOptions.isExpanded)
                {
                    EditorGUILayout.PropertyField(defaultSaveOptions, GUIContent.none);
                    EditorGUI.indentLevel++;
                    //ensureSharedColors.boolValue = EditorGUILayout.ToggleLeft(new GUIContent(ensureSharedColors.displayName, ensureSharedColors.tooltip), ensureSharedColors.boolValue);
                    //makeUniqueFilename.boolValue = EditorGUILayout.ToggleLeft(new GUIContent(makeUniqueFilename.displayName, makeUniqueFilename.tooltip), makeUniqueFilename.boolValue);
                    //just drawing these as propertyFields because the toolTip on toggle left doesn't work
                    EditorGUILayout.PropertyField(ensureSharedColors);
                    EditorGUILayout.PropertyField(makeUniqueFilename);
                    EditorGUI.indentLevel--;
                }
                EditorGUI.indentLevel--;
                if (Application.isPlaying)
                {
                    if (GUILayout.Button("Perform Save"))
                    {
                        thisDCA.DoSave();
                    }
                }
                EditorGUILayout.Space();
            }
            if (EditorGUI.EndChangeCheck())
            {
                serializedObject.ApplyModifiedProperties();
            }
            GUILayout.Space(2f);
            //for CharacterEvents
            EditorGUI.BeginChangeCheck();
            SerializedProperty CharacterCreated = serializedObject.FindProperty("CharacterCreated");

            CharacterCreated.isExpanded = EditorGUILayout.Foldout(CharacterCreated.isExpanded, "Character Events");
            if (CharacterCreated.isExpanded)
            {
                SerializedProperty CharacterBegun      = serializedObject.FindProperty("CharacterBegun");
                SerializedProperty CharacterUpdated    = serializedObject.FindProperty("CharacterUpdated");
                SerializedProperty CharacterDestroyed  = serializedObject.FindProperty("CharacterDestroyed");
                SerializedProperty CharacterDnaUpdated = serializedObject.FindProperty("CharacterDnaUpdated");
                SerializedProperty RecipeUpdated       = serializedObject.FindProperty("RecipeUpdated");
                SerializedProperty AnimatorSaved       = serializedObject.FindProperty("AnimatorStateSaved");
                SerializedProperty AnimatorRestored    = serializedObject.FindProperty("AnimatorStateRestored");

                EditorGUILayout.PropertyField(CharacterBegun);
                EditorGUILayout.PropertyField(CharacterCreated);
                EditorGUILayout.PropertyField(CharacterUpdated);
                EditorGUILayout.PropertyField(CharacterDestroyed);
                EditorGUILayout.PropertyField(CharacterDnaUpdated);
                EditorGUILayout.PropertyField(RecipeUpdated);
                EditorGUILayout.PropertyField(AnimatorSaved);
                EditorGUILayout.PropertyField(AnimatorRestored);
            }
            if (EditorGUI.EndChangeCheck())
            {
                serializedObject.ApplyModifiedProperties();
            }
            GUILayout.Space(2f);
            //for AdvancedOptions
            EditorGUI.BeginChangeCheck();
            context.isExpanded = EditorGUILayout.Foldout(context.isExpanded, "Advanced Options");
            if (context.isExpanded)
            {
                EditorGUI.BeginChangeCheck();
                EditorGUILayout.PropertyField(serializedObject.FindProperty("hide"));
                EditorGUILayout.PropertyField(serializedObject.FindProperty("AtlasResolutionScale"));
                EditorGUILayout.PropertyField(serializedObject.FindProperty("defaultRendererAsset"));

                if (EditorGUI.EndChangeCheck())
                {
                    serializedObject.ApplyModifiedProperties();
                }
                if (showHelp)
                {
                    EditorGUILayout.HelpBox("Hide: This disables the display of the Avatar without preventing it from being generated. If you want to prevent the character from being generated at all disable the DynamicCharacterAvatar component itself.", MessageType.Info);
                }
                //for _buildCharacterEnabled we want to set the value using the DCS BuildCharacterEnabled property because this actually triggers BuildCharacter
                var buildCharacterEnabled      = serializedObject.FindProperty("_buildCharacterEnabled");
                var buildCharacterEnabledValue = buildCharacterEnabled.boolValue;
                EditorGUI.BeginChangeCheck();
                var buildCharacterEnabledNewValue = EditorGUILayout.Toggle(new GUIContent(buildCharacterEnabled.displayName, "Builds the character on recipe load or race changed. If you want to load multiple recipes into a character you can disable this and enable it when you are done. By default this should be true."), buildCharacterEnabledValue);
                if (EditorGUI.EndChangeCheck())
                {
                    if (buildCharacterEnabledNewValue != buildCharacterEnabledValue)
                    {
                        thisDCA.BuildCharacterEnabled = buildCharacterEnabledNewValue;
                    }
                    serializedObject.ApplyModifiedProperties();
                }
                if (showHelp)
                {
                    EditorGUILayout.HelpBox("Build Character Enabled: Builds the character on recipe load or race changed. If you want to load multiple recipes into a character you can disable this and enable it when you are done. By default this should be true.", MessageType.Info);
                }
                EditorGUILayout.PropertyField(serializedObject.FindProperty("loadBlendShapes"), new GUIContent("Load BlendShapes"));
                EditorGUILayout.PropertyField(serializedObject.FindProperty("keepAvatar"), new GUIContent("Keep Avatar"));
                EditorGUILayout.PropertyField(serializedObject.FindProperty("KeepAnimatorController"), new GUIContent("Keep Animator Controller"));
                EditorGUILayout.PropertyField(context);
                EditorGUILayout.PropertyField(umaData);
                EditorGUILayout.PropertyField(umaGenerator);
                EditorGUILayout.Space();
                EditorGUILayout.PropertyField(umaRecipe);
                EditorGUILayout.PropertyField(animationController);
                EditorGUILayout.PropertyField(serializedObject.FindProperty("BoundsOffset"));
            }
            if (EditorGUI.EndChangeCheck())
            {
                serializedObject.ApplyModifiedProperties();
            }
            GUILayout.Space(2f);
            //for PlaceholderOptions
            EditorGUI.BeginChangeCheck();
            SerializedProperty gizmo          = serializedObject.FindProperty("showPlaceholder");
            SerializedProperty enableGizmo    = serializedObject.FindProperty("showPlaceholder");
            SerializedProperty previewModel   = serializedObject.FindProperty("previewModel");
            SerializedProperty customModel    = serializedObject.FindProperty("customModel");
            SerializedProperty customRotation = serializedObject.FindProperty("customRotation");
            SerializedProperty previewColor   = serializedObject.FindProperty("previewColor");

            gizmo.isExpanded = EditorGUILayout.Foldout(gizmo.isExpanded, "Placeholder Options");
            if (gizmo.isExpanded)
            {
                EditorGUILayout.PropertyField(enableGizmo);
                EditorGUILayout.PropertyField(previewModel);
                if (previewModel.enumValueIndex == 2)
                {
                    EditorGUILayout.PropertyField(customModel);
                    EditorGUILayout.PropertyField(customRotation);
                }
                EditorGUILayout.PropertyField(previewColor);
            }
            if (EditorGUI.EndChangeCheck())
            {
                serializedObject.ApplyModifiedProperties();
            }

            if (Application.isPlaying)
            {
                showWardrobe = EditorGUILayout.Foldout(showWardrobe, "Current Wardrobe");
                if (showWardrobe)
                {
                    EditorGUI.indentLevel++;
                    Dictionary <string, UMATextRecipe> currentWardrobe = thisDCA.WardrobeRecipes;

                    foreach (KeyValuePair <string, UMATextRecipe> item in currentWardrobe)
                    {
                        GUILayout.BeginHorizontal();
                        EditorGUI.BeginDisabledGroup(true);
                        EditorGUILayout.LabelField(item.Key, GUILayout.Width(88.0f));
                        EditorGUILayout.TextField(item.Value.DisplayValue + " (" + item.Value.name + ")");
                        EditorGUI.EndDisabledGroup();
                        if (GUILayout.Button("Inspect", EditorStyles.toolbarButton, GUILayout.Width(40)))
                        {
                            InspectorUtlity.InspectTarget(item.Value);
                        }
                        GUILayout.EndHorizontal();
                    }
                    EditorGUI.indentLevel--;
                }
            }
        }