Пример #1
0
        /// <summary>
        /// Initialize the HumanoidBuilder. This must be called first before trying to use the builder to create UMAs.
        /// </summary>
        /// <param name='scale'>
        /// The atlas reduction scale. 1 = no reduction. 0.5 = reduce by half.
        /// </param>
        public static void Initialize(float scale = 1)
        {
            // find our objects
            GameObject tmp = GameObject.Find("RaceLibrary");

            if (tmp == null)
            {
                Debug.LogError("UMAElements.HumanoidBuilder.Initialize: Could not find UMA RaceLibrary");
            }
            else
            {
                _raceLibrary = tmp.GetComponentInChildren <RaceLibrary>();
            }

            tmp = GameObject.Find("UMAGenerator");
            if (tmp == null)
            {
                Debug.LogError("UMAElements.HumanoidBuilder.Initialize: Could not find UMAGenerator");
            }
            else
            {
                _generator = tmp.GetComponentInChildren <UMAGenerator>();
            }

            // set the atlas resolution scale
            _atlasScale = scale;
            // we've been initialized
            _initialized = true;
            _charList    = new List <Humanoid>();
        }
Пример #2
0
    void Initialize()
    {
        UMAInstance();

        gameObject = new GameObject(objectName);
        UpdateVec();

        umaContext = UMAContext.FindInstance();
        UMAGenerator generator = umaContext.umaGenerator;

        umaDynamicAvatar = gameObject.AddComponent <UMADynamicAvatar>();
        umaDynamicAvatar.Initialize();

        UMAData umaData = umaDynamicAvatar.umaData;

        umaDynamicAvatar.umaGenerator = generator;
        umaData.umaGenerator          = generator;

        UMATextRecipe recipe = UMATextRecipe.CreateInstance <UMATextRecipe>();

        recipe.Load(umaData.umaRecipe, umaContext);
        umaDynamicAvatar.umaRecipe = recipe;
        umaData.AddAdditionalRecipes(new UMARecipeBase[] { umaContext.umaTextRecipe }, umaContext);
        umaData.OnCharacterCreated   += CharacterCreated;
        umaData.OnCharacterUpdated   += CharacterUpdated;
        umaData.OnCharacterDestroyed += CharacterDestroyed;

        if (isExpress)
        {
            expressionPlayer = gameObject.AddComponent <UMAExpressionPlayer>();
            expressionPlayer.overrideMecanimEyes = true;
            expressionPlayer.overrideMecanimHead = true;
            expressionPlayer.overrideMecanimJaw  = true;
            expressionPlayer.overrideMecanimNeck = true;
        }

        umaData.umaRecipe.slotDataList = new SlotData[100];
        UMADnaHumanoid umaDna         = new UMADnaHumanoid();
        UMADnaTutorial umaTutorialDNA = new UMADnaTutorial();

        umaData.umaRecipe.AddDna(umaDna);
        umaData.umaRecipe.AddDna(umaTutorialDNA);

        ICharacterSlotOverly characterSlotOverlay = new CharacterSlotOverly(umaDynamicAvatar);

        characterAnim = new CharacterAnim(umaDynamicAvatar);
        //characterDna = new CharacterDna(umaDna, umaData, characterAnim, characterData);
        characterBase  = new CharacterBase(resType, characterSlotOverlay, umaData, umaDynamicAvatar, characterData);
        characterCloth = new CharacterCloth(resType, characterData, characterSlotOverlay, this, characterBase);
    }
Пример #3
0
        static void CreatePrimitiveUma()//Spawn a UMA charater and save its recipe in 'SavedRecipes' folder
        {
            UMAGenerator generator = MonoBehaviour.FindObjectOfType <UMAGenerator>();

            GameObject uma = new GameObject();

            uma.name = "A primitive UMA";
            UMADynamicAvatar dynamicAvator = uma.AddComponent <UMADynamicAvatar>();

            dynamicAvator.loadOnStart = true;

            //animator
            string[] animator     = AssetDatabase.FindAssets("ThirdPerson t: RuntimeAnimatorController"); // Standard asset animator
            string   animatorPath = AssetDatabase.GUIDToAssetPath(animator[0]);

            dynamicAvator.animationController = AssetDatabase.LoadAssetAtPath <RuntimeAnimatorController>(animatorPath);

            //npc movement script
            UMAController umaController = uma.AddComponent <UMAController>();

            umaController.speed = 0.4f;

            //character controller
            CharacterController characterController = uma.AddComponent <CharacterController>();

            characterController.center = new Vector3(0, 1.0f, 0);
            //Recipe mixer
            UMA.Examples.UMARecipeMixer[] recipesMixer = MonoBehaviour.FindObjectsOfType <UMA.Examples.UMARecipeMixer>();

            dynamicAvator.context      = MonoBehaviour.FindObjectOfType <UMAContext>();
            dynamicAvator.umaGenerator = generator;
            dynamicAvator.Initialize();
            UMAData umaData = dynamicAvator.umaData;

            umaData.atlasResolutionScale = 1.0f;

            RecipeMixerController recipeMixerController = MonoBehaviour.FindObjectOfType <RecipeMixerController>();

            RandomizeRecipe(umaData
                            , recipesMixer
                            , dynamicAvator.context
                            , recipeMixerController.sharedColors);

            RandomizeDNA(umaData);

            SaveRecipe(umaData, dynamicAvator.context);

            dynamicAvator.Show();
        }
Пример #4
0
        static void InitializeUMA()
        {//Initialize UMA context
         // UMA
            GameObject uma = new GameObject();

            uma.name = "UMA";
            GameObject parent;

            if (parent = Selection.activeGameObject)
            {
                uma.transform.SetParent(parent.transform);
            }

            // Race Library
            GameObject races = new GameObject();

            races.name = "RaceLibrary";
            races.transform.SetParent(uma.transform);
            RaceLibrary raceLibrary = races.AddComponent <RaceLibrary>();

            //null search in all assets folder, t means type, so we are searching Uma.RaceData
            string[] racesData = AssetDatabase.FindAssets("t: RaceData", null);
            foreach (string data in racesData)
            {
                //get the path
                string   racePath  = AssetDatabase.GUIDToAssetPath(data);
                RaceData raceAsset = AssetDatabase.LoadAssetAtPath <RaceData>(racePath);
                raceLibrary.AddRace(raceAsset);
            }

            // Slots
            GameObject slots = new GameObject();

            slots.name = "SlotLibrary";
            slots.transform.SetParent(uma.transform);

            SlotLibrary slotLibrary = slots.AddComponent <SlotLibrary>();

            //null search in all assets folder, t means type, so we are searching Uma.RaceData
            string[] slotsData = AssetDatabase.FindAssets("t: SlotDataAsset", null);
            foreach (string data in slotsData)
            {
                //get the path
                string        slotPath  = AssetDatabase.GUIDToAssetPath(data);
                SlotDataAsset slotAsset = AssetDatabase.LoadAssetAtPath <SlotDataAsset>(slotPath);
                slotLibrary.AddSlotAsset(slotAsset);
            }

            // Overlays
            GameObject overlays = new GameObject();

            overlays.name = "OverlayLibrary";
            overlays.transform.SetParent(uma.transform);

            OverlayLibrary overlayLibrary = overlays.AddComponent <OverlayLibrary>();

            //null search in all assets folder, t means type, so we are searching Uma.RaceData
            string[] overlaysData = AssetDatabase.FindAssets("t: OverlayDataAsset", null);
            foreach (string data in overlaysData)
            {
                //get the path
                string           overlayPath  = AssetDatabase.GUIDToAssetPath(data);
                OverlayDataAsset overlayAsset = AssetDatabase.LoadAssetAtPath <OverlayDataAsset>(overlayPath);
                overlayLibrary.AddOverlayAsset(overlayAsset);
            }

            // Context
            GameObject context = new GameObject();

            context.name = "ContextLibrary";
            context.transform.SetParent(uma.transform);

            UMAContext umaContext = context.AddComponent <UMAContext>();

            umaContext.raceLibrary    = raceLibrary;
            umaContext.slotLibrary    = slotLibrary;
            umaContext.overlayLibrary = overlayLibrary;

            // Generators
            UMAGenerator generator = MonoBehaviour.Instantiate <UMAGenerator>
                                         (AssetDatabase.LoadAssetAtPath <UMAGenerator>(CommonNames.umaFolderGeneratorPrefabPath));

            generator.name = "UMAGenerator";
            generator.transform.SetParent(uma.transform);

            UMADefaultMeshCombiner meshCombiner = generator.gameObject.AddComponent <UMADefaultMeshCombiner>();

            generator.meshCombiner = meshCombiner;

            //Mixers for random UMA creation
            //Male
            GameObject maleRecipeMixer = new GameObject();

            maleRecipeMixer.name = "MaleRecipeMixer";
            UMA.Examples.UMARecipeMixer maleRecipeMixerScript = maleRecipeMixer.AddComponent <UMA.Examples.UMARecipeMixer>();
            maleRecipeMixerScript.raceData = raceLibrary.GetRace("HumanMale");

            UMA.Examples.UMARecipeMixer.RecipeSection[] maleRecipeSection = new UMA.Examples.UMARecipeMixer.RecipeSection[3];

            //Male Recipe Section : Body
            maleRecipeSection[0]               = new UMA.Examples.UMARecipeMixer.RecipeSection();
            maleRecipeSection[0].name          = "Body";
            maleRecipeSection[0].selectionRule = UMA.Examples.UMARecipeMixer.SelectionType.IncludeOne;
            maleRecipeSection[0].recipes       = new UMARecipeBase[2];
            string[] maleBodyRecipePath = AssetDatabase.FindAssets("MaleBase t: UMATextRecipe", null);
            maleRecipeSection[0].recipes[0] = AssetDatabase.LoadAssetAtPath <UMATextRecipe>(AssetDatabase.GUIDToAssetPath(maleBodyRecipePath[0]));
            string[] maleBody2RecipePath = AssetDatabase.FindAssets("MaleBase2 t: UMATextRecipe", null);
            maleRecipeSection[0].recipes[1] = AssetDatabase.LoadAssetAtPath <UMATextRecipe>(AssetDatabase.GUIDToAssetPath(maleBody2RecipePath[0]));

            //Male Recipe Section : Underwear
            maleRecipeSection[1]               = new UMA.Examples.UMARecipeMixer.RecipeSection();
            maleRecipeSection[1].name          = "Clothing";
            maleRecipeSection[1].selectionRule = UMA.Examples.UMARecipeMixer.SelectionType.IncludeOne;
            maleRecipeSection[1].recipes       = new UMARecipeBase[1];
            //string[] maleUnderwearRecipePath = AssetDatabase.FindAssets("MaleUnderwear t: UMATextRecipe", null);
            //maleRecipeSection[1].recipes[0] = AssetDatabase.LoadAssetAtPath<UMATextRecipe>(AssetDatabase.GUIDToAssetPath(maleUnderwearRecipePath[0]));
            string[] maleOutfit1RecipePath = AssetDatabase.FindAssets("MaleOutfit1 t: UMATextRecipe", null);
            foreach (string hairPath in maleOutfit1RecipePath)
            {
                UMATextRecipe umaTextRecipe = AssetDatabase.LoadAssetAtPath <UMATextRecipe>(AssetDatabase.GUIDToAssetPath(hairPath));
                if (umaTextRecipe.name == "MaleOutfit1")
                {
                    maleRecipeSection[1].recipes[0] = umaTextRecipe;
                }
            }

            //Male Recipe Section : Hair
            maleRecipeSection[2]               = new UMA.Examples.UMARecipeMixer.RecipeSection();
            maleRecipeSection[2].name          = "Hair";
            maleRecipeSection[2].selectionRule = UMA.Examples.UMARecipeMixer.SelectionType.IncludeSome;
            maleRecipeSection[2].recipes       = new UMARecipeBase[2];
            string[] maleBeardRecipePath = AssetDatabase.FindAssets("MaleBeard t: UMATextRecipe", null);
            foreach (string hairPath in maleBeardRecipePath)
            {
                UMATextRecipe umaTextRecipe = AssetDatabase.LoadAssetAtPath <UMATextRecipe>(AssetDatabase.GUIDToAssetPath(hairPath));
                if (umaTextRecipe.name == "MaleBeard")
                {
                    maleRecipeSection[2].recipes[0] = umaTextRecipe;
                }
            }
            string[] maleHairRecipePath = AssetDatabase.FindAssets("MaleHair t: UMATextRecipe", null);
            foreach (string hairPath in maleHairRecipePath)
            {
                UMATextRecipe umaTextRecipe = AssetDatabase.LoadAssetAtPath <UMATextRecipe>(AssetDatabase.GUIDToAssetPath(hairPath));
                if (umaTextRecipe.name == "MaleHair")
                {
                    maleRecipeSection[2].recipes[1] = umaTextRecipe;
                }
            }

            maleRecipeMixerScript.recipeSections = maleRecipeSection;

            maleRecipeMixer.GetComponent <Transform>().SetParent(uma.transform);

            //Female
            GameObject femaleRecipeMixer = new GameObject();

            femaleRecipeMixer.name = "FemaleRecipeMixer";
            UMA.Examples.UMARecipeMixer femaleRecipeMixerScript = femaleRecipeMixer.AddComponent <UMA.Examples.UMARecipeMixer>();
            femaleRecipeMixerScript.raceData = raceLibrary.GetRace("HumanFemale");
            UMA.Examples.UMARecipeMixer.RecipeSection[] femaleRecipeSection = new UMA.Examples.UMARecipeMixer.RecipeSection[3];

            //Female Recipe Section : Body
            femaleRecipeSection[0]               = new UMA.Examples.UMARecipeMixer.RecipeSection();
            femaleRecipeSection[0].name          = "Body";
            femaleRecipeSection[0].selectionRule = UMA.Examples.UMARecipeMixer.SelectionType.IncludeOne;
            femaleRecipeSection[0].recipes       = new UMARecipeBase[1];
            string[] femaleBodyRecipePath = AssetDatabase.FindAssets("HumanFemale Base Recipe t: UMATextRecipe", null);
            femaleRecipeSection[0].recipes[0] = AssetDatabase.LoadAssetAtPath <UMATextRecipe>(AssetDatabase.GUIDToAssetPath(femaleBodyRecipePath[0]));

            //Female Recipe Section : Underwear
            femaleRecipeSection[1]               = new UMA.Examples.UMARecipeMixer.RecipeSection();
            femaleRecipeSection[1].name          = "Clothing";
            femaleRecipeSection[1].selectionRule = UMA.Examples.UMARecipeMixer.SelectionType.IncludeOne;
            femaleRecipeSection[1].recipes       = new UMARecipeBase[2];
            //string[] femaleUnderwearRecipePath = AssetDatabase.FindAssets("FemaleUnderwear t: UMATextRecipe", null);
            string[] femaleOutfit1RecipePath = AssetDatabase.FindAssets("FemaleOutfit1 t: UMATextRecipe", null);
            string[] femaleOutfit2RecipePath = AssetDatabase.FindAssets("FemaleOutfit2 t: UMATextRecipe", null);
            //femaleRecipeSection[1].recipes[0] = AssetDatabase.LoadAssetAtPath<UMATextRecipe>(AssetDatabase.GUIDToAssetPath(femaleUnderwearRecipePath[0]));
            femaleRecipeSection[1].recipes[0] = AssetDatabase.LoadAssetAtPath <UMATextRecipe>(AssetDatabase.GUIDToAssetPath(femaleOutfit1RecipePath[0]));
            femaleRecipeSection[1].recipes[1] = AssetDatabase.LoadAssetAtPath <UMATextRecipe>(AssetDatabase.GUIDToAssetPath(femaleOutfit2RecipePath[0]));

            //Female Recipe Section : Hair
            femaleRecipeSection[2]               = new UMA.Examples.UMARecipeMixer.RecipeSection();
            femaleRecipeSection[2].name          = "Hair";
            femaleRecipeSection[2].selectionRule = UMA.Examples.UMARecipeMixer.SelectionType.IncludeOne;
            femaleRecipeSection[2].recipes       = new UMARecipeBase[3];
            string[] femaleHairRecipePath      = AssetDatabase.FindAssets("FemaleHair t: UMATextRecipe", null);
            string[] femaleHairLongRecipePath  = AssetDatabase.FindAssets("FemaleHairLong t: UMATextRecipe", null);
            string[] femaleHairShortRecipePath = AssetDatabase.FindAssets("FemaleHairShort t: UMATextRecipe", null);

            foreach (string hairPath in femaleHairRecipePath)
            {
                UMATextRecipe umaTextRecipe = AssetDatabase.LoadAssetAtPath <UMATextRecipe>(AssetDatabase.GUIDToAssetPath(hairPath));
                if (umaTextRecipe.name == "FemaleHair")
                {
                    femaleRecipeSection[2].recipes[0] = umaTextRecipe;
                }
            }

            femaleRecipeSection[2].recipes[1] = AssetDatabase.LoadAssetAtPath <UMATextRecipe>(AssetDatabase.GUIDToAssetPath(femaleHairLongRecipePath[0]));
            femaleRecipeSection[2].recipes[2] = AssetDatabase.LoadAssetAtPath <UMATextRecipe>(AssetDatabase.GUIDToAssetPath(femaleHairShortRecipePath[0]));

            femaleRecipeMixerScript.recipeSections = femaleRecipeSection;

            femaleRecipeMixer.GetComponent <Transform>().SetParent(uma.transform);

            //Shared colors table
            GameObject recipeMixerController = new GameObject();

            recipeMixerController.name = "RecipeMixerController";
            RecipeMixerController recipeMixerControllerScript = recipeMixerController.AddComponent <RecipeMixerController>();

            SharedColorTable[] sharedColorTable = recipeMixerControllerScript.sharedColors;

            string[][] sharedColorsPath = new string[5][];
            sharedColorsPath[0] = AssetDatabase.FindAssets("HumanHairLinear", null);
            sharedColorsPath[1] = AssetDatabase.FindAssets("HumanSkinLinear", null);
            sharedColorsPath[2] = AssetDatabase.FindAssets("ClothingUnderwear", null);
            sharedColorsPath[3] = AssetDatabase.FindAssets("ClothingTops", null);
            sharedColorsPath[4] = AssetDatabase.FindAssets("ClothingBottoms", null);

            sharedColorTable[0] = AssetDatabase.LoadAssetAtPath <SharedColorTable>(AssetDatabase.GUIDToAssetPath(sharedColorsPath[0][0]));
            sharedColorTable[1] = AssetDatabase.LoadAssetAtPath <SharedColorTable>(AssetDatabase.GUIDToAssetPath(sharedColorsPath[1][0]));
            sharedColorTable[2] = AssetDatabase.LoadAssetAtPath <SharedColorTable>(AssetDatabase.GUIDToAssetPath(sharedColorsPath[2][0]));
            sharedColorTable[3] = AssetDatabase.LoadAssetAtPath <SharedColorTable>(AssetDatabase.GUIDToAssetPath(sharedColorsPath[3][0]));
            sharedColorTable[4] = AssetDatabase.LoadAssetAtPath <SharedColorTable>(AssetDatabase.GUIDToAssetPath(sharedColorsPath[4][0]));

            recipeMixerController.transform.SetParent(uma.transform);
        }
Пример #5
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();
                    }
                }
            }
        }