Beispiel #1
0
        // ----- ------ Avatar ----- -----
        public static Dictionary <string, VRCAvatarDescriptor> GetAvatars(out bool crossScene)
        {
            crossScene = false;
            Dictionary <string, VRCAvatarDescriptor> avatars = new Dictionary <string, VRCAvatarDescriptor>();

            for (int i = 0; i < SceneManager.sceneCount; i++)
            {
                Scene scene = SceneManager.GetSceneAt(i);
                if (!scene.isLoaded)
                {
                    continue;
                }

                GameObject[] rootObjects = scene.GetRootGameObjects();
                foreach (GameObject root in rootObjects)
                {
                    VRCAvatarDescriptor avatar = root.GetComponent <VRCAvatarDescriptor>();
                    if (null != avatar)
                    {
                        avatars.Add(TEA_Manager.GetSceneAvatarKey(scene, avatar), avatar);
                        if (scene != SceneManager.GetActiveScene())
                        {
                            crossScene = true;
                        }
                    }
                }
            }
            return(avatars);
        }
Beispiel #2
0
 private void Awake()
 {
     current = this;
     System.Random random = new System.Random();
     id = random.NextDouble();
     Debug.Log($"TEA_Manager awake [{id}]");
 }
Beispiel #3
0
        public bool ManagerSetup(bool play, bool _play, bool _compile)
        {
            List <TEA_Manager> managers = new List <TEA_Manager>();

            manager = null;
            int  activeCount = 0;
            bool destroy     = (!play || !_play || !_compile) && !settings.keepInScene;

            for (int i = 0; i < SceneManager.sceneCount; i++)
            {
                Scene scene = SceneManager.GetSceneAt(i);
                if (!scene.isLoaded)
                {
                    continue;
                }
                int count = 0;

                foreach (GameObject obj in scene.GetRootGameObjects())
                {
                    Component comp = obj.GetComponentInChildren(typeof(TEA_Manager), true);
                    if (null != comp)
                    {
                        count++;
                        TEA_Manager manager = (TEA_Manager)comp;

                        if (!play && (count > 1 || destroy || scene != SceneManager.GetActiveScene()))
                        {
                            DestroyImmediate(manager.gameObject);
                        }
                        else if (scene == SceneManager.GetActiveScene())
                        {
                            this.manager = manager;
                            activeCount++;
                        }
                    } //exists
                }     //for obj
            }         // for scene

            // add managers
            if (null == manager && _avatars && (_compile || _play || play || settings.keepInScene))
            {
                TEA_Manager newManager = Instantiate(prefabObject).GetComponent <TEA_Manager>();
                this.manager = newManager;
            }
            return(activeCount > 1);
        }
Beispiel #4
0
        private bool Initialized()
        {
            if (_initialized)
            {
                return(true);
            }

            Avatar = TEA_Manager.current.Avatar;

            if (null == Avatar)
            {
                return(false);
            }

            newPosition        = Avatar.transform.position;
            horizontalRotation = Avatar.transform.rotation;

            //--- paramters ---
            mainMenu   = Avatar.expressionsMenu;
            parameters = Avatar.expressionParameters;
            avatarAnim = Avatar.gameObject.GetComponent <Animator>();
            avatarAnim.runtimeAnimatorController = TEA_Manager.current.Controllers[TEA_Manager.AvatarIndex()];
            Grounded = true;
            avatarAnim.SetBool("Grounded", Grounded);

            TEA_PlayableLayerData layerData = TEA_Manager.current.LayerInfo[TEA_Manager.AvatarIndex()];

            TEA_PlayableLayerData.PlayableLayerData data = layerData.FindPlayableLayerData(VRCAvatarDescriptor.AnimLayerType.Base);
            for (int i = data.start; i < data.end; i++)
            {
                avatarAnim.SetLayerWeight(i, 1);
            }

            //--- events ---
            controlEvents = new Dictionary <VRC.SDKBase.VRC_PlayableLayerControl.BlendableLayer, TEA_PlayableLayerControl>();
            if (null == TEA_PlayableLayerControl.ApplySettings)
            {
                TEA_PlayableLayerControl.ApplySettings += TEA_PlayableLayerEvent;
            }

            _initialized = true;
            return(true);
        }
Beispiel #5
0
 public void OnTEAManagerUpdate(TEA_Manager tea_manager)
 {
     _initialized = false;
     Start();
 }
Beispiel #6
0
        private void Update()
        {
            if (!Initialized())
            {
                return;
            }

            //--- controls ---
            List <VRCPlayableLayerControl.BlendableLayer> remove = new List <VRC.SDKBase.VRC_PlayableLayerControl.BlendableLayer>();

            foreach (KeyValuePair <VRCPlayableLayerControl.BlendableLayer, TEA_PlayableLayerControl> item in controlEvents)
            {
                TEA_PlayableLayerData layerData = TEA_Manager.current.LayerInfo[TEA_Manager.AvatarIndex()];
                TEA_PlayableLayerData.PlayableLayerData data = layerData.FindPlayableLayerData(TEA_PlayableLayerControl.AnimLayerType(item.Value.layer));
                float prevDur = item.Value.duration;
                item.Value.duration += Time.deltaTime;
                float normalized = item.Value.duration / item.Value.blendDuration;
                for (int i = data.start; i < data.end; i++)
                {
                    if (normalized >= 1)
                    {
                        item.Value.animator.SetLayerWeight(i, item.Value.goalWeight);
                        remove.Add(item.Value.layer);
                    }
                    else
                    {
                        float newWeight = Mathf.Lerp(item.Value.animator.GetLayerWeight(i), item.Value.goalWeight, (item.Value.duration - prevDur) / (item.Value.blendDuration - prevDur));
                        item.Value.animator.SetLayerWeight(i, newWeight);
                    }
                }
            }

            foreach (VRCPlayableLayerControl.BlendableLayer rm in remove)
            {
                controlEvents.Remove(rm);
            }

            if (CameraController.mouseIn && Input.GetMouseButton(1) && !CameraController.FreeCamera)
            {
                newPosition = Vector3.zero;
                Avatar.transform.position = newPosition;
                VelocityX = 0;
                VelocityZ = 0;
            }
            else if (null != Locomotion && CameraController.mouseIn && !CameraController.FreeCamera)
            {
                //Rotate
                float turnAmount = Mathf.Ceil(Locomotion.RotationAmount * Time.deltaTime);
                if (Input.GetKey(KeyCode.E))
                {
                    horizontalRotation *= Quaternion.Euler(Vector3.up * turnAmount);
                }
                if (Input.GetKey(KeyCode.Q))
                {
                    horizontalRotation *= Quaternion.Euler(Vector3.up * -turnAmount);
                }
                Avatar.transform.rotation = horizontalRotation;

                // --- input ---
                if (Input.GetKeyUp(KeyCode.LeftShift))
                {
                    speed++;
                }
                if (3 <= speed)
                {
                    speed = 0;
                }

                if (0 == speed)
                {
                    Locomotion.MoveType = TEA_Settings.MoveTypes.Walk;
                    velocity            = Locomotion.WalkVelocity;
                }
                else if (1 == speed)
                {
                    Locomotion.MoveType = TEA_Settings.MoveTypes.Run;
                    velocity            = Locomotion.RunVelocity;
                }
                else if (2 == speed)
                {
                    Locomotion.MoveType = TEA_Settings.MoveTypes.Sprint;
                    velocity            = Locomotion.SprintVelocity;
                }

                // Walk
                int forward  = Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow) ? 1 : 0;
                int backward = Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow) ? -1 : 0;
                int right    = Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow) ? 1 : 0;
                int left     = Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow) ? -1 : 0;
                int z        = forward + backward;
                int x        = right + left;

                if (x != 0 || z != 0)
                {
                    float   distance        = Time.deltaTime * velocity;
                    float   theta           = Mathf.Atan2(z, x);
                    float   distanceX       = Mathf.Cos(theta) * (distance);
                    float   distanceZ       = Mathf.Sin(theta) * (distance);
                    Vector3 cameraDirection = CameraController.RigCamera.transform.forward;

                    // Animator Velocities
                    if (TEA_Manager.current.ViewPort.gameObject.activeSelf)
                    {
                        newPosition = TEA_Utility.TransformPoint(Avatar.transform, new Vector3(distanceX, 0, distanceZ));
                        VelocityZ   = distanceZ / Time.deltaTime;
                    }
                    else
                    {
                        newPosition += TEA_Manager.current.CameraRigPointer.transform.right * distanceX;
                        newPosition += TEA_Manager.current.CameraRigPointer.transform.forward * distanceZ;
                        Vector3 movePoint  = TEA_Utility.InverseTransformPoint(Avatar.transform, newPosition);
                        float   aTheta     = Mathf.Deg2Rad * Avatar.transform.rotation.eulerAngles.y;
                        Vector3 movePointR = new Vector3();
                        movePointR.x = movePoint.x * Mathf.Cos(aTheta) - movePoint.z * Mathf.Sin(aTheta);
                        movePointR.z = movePoint.z * Mathf.Cos(aTheta) + movePoint.x * Mathf.Sin(aTheta);
                        VelocityX    = 0 + movePointR.x / Time.deltaTime;
                        VelocityZ    = 0 + movePointR.z / Time.deltaTime;
                    }

                    //Debug.Log($"[{x},{z}] distance[{distance}] float[{distanceX}, {distanceZ}] velocity[{VelocityX}, {VelocityZ}]");

                    // world position
                    Avatar.transform.position = newPosition;
                }
                else
                {
                    newPosition = Avatar.transform.position;
                    VelocityX   = 0;
                    VelocityZ   = 0;
                }
            }
            else
            {
                newPosition = Avatar.transform.position;
                VelocityX   = 0;
                VelocityZ   = 0;
            }
        }
Beispiel #7
0
	public bool CompileAnimators(TEA_Manager manager, TEA_Settings settings) {
	 WorkingDirPath = ASSETS_CONTENT + settings.WorkingDirectory;
	 WorkingDirContent = WorkingDirPath + "/";

	 try {
		// working folder
		if(!AssetDatabase.IsValidFolder(WorkingDirPath)) {
		 if(string.IsNullOrEmpty(AssetDatabase.CreateFolder("Assets", settings.WorkingDirectory))) {
			EditorUtility.DisplayDialog(ERROR_HEADER, $"Could not create working folder [{WorkingDirPath}]", "ok");
			return true;
		 }
		}

		List<TEA_ValidationIssues> avatarIssues = new List<TEA_ValidationIssues>();
		validationIssue = false;
		AnimatorController teaAnimContr = GenerateTEA_Animator(manager);

		foreach(string path in AssetDatabase.GetSubFolders(WorkingDirPath)) {
		 AssetDatabase.DeleteAsset(path);
		}

		int aCount = 0;
		// --- --- --- for all avatars
		foreach(VRCAvatarDescriptor avatar in TEA_Manager.AvatarDescriptor) {
		 //Scene Folder
		 string sceneFolder = GetPath(false, WorkingDirPath, TEA_Manager.AvatarDescriptor[aCount].gameObject.scene.name);
		 if(!AssetDatabase.IsValidFolder(sceneFolder)) {
			if(string.IsNullOrEmpty(AssetDatabase.CreateFolder(WorkingDirPath, TEA_Manager.AvatarDescriptor[aCount].gameObject.scene.name))) {
			 EditorUtility.DisplayDialog(ERROR_HEADER, $"Could not create working folder [{sceneFolder}]", "ok");
			 return true;
			}
		 }

		 drivers = new List<DriverIssue>();
		 VRCAvatarDescriptor avatarComp = TEA_Manager.AvatarDescriptor[aCount];
		 currentAvatar = avatarComp;
		 issues = TEA_ValidationIssues.CreateInstance<TEA_ValidationIssues>();
		 issues.AvatarName = avatarComp.name;
		 string avatarKey = avatarComp.gameObject.name;

		 //Debug.Log($"----- Creating animator controllers for [{avatarKey}]");

		 // avatar folder
		 string folderPath = GetPath(false, sceneFolder, avatarKey);
		 if(string.IsNullOrEmpty(AssetDatabase.CreateFolder(sceneFolder, avatarKey))) {
			EditorUtility.DisplayDialog(ERROR_HEADER, $"Could not create working folder [{folderPath}]", "ok");
			return true;
		 }

		 //--- Animator ---
		 superAnimator = new AnimatorController() { name = CONTROLLER_PREFIX + avatarKey };
		 TEA_PlayableLayerData layerInfo = TEA_PlayableLayerData.CreateInstance<TEA_PlayableLayerData>();
		 layerInfo.AvatarName = avatarKey;
		 layerInfo.name = avatarKey + "-layerData";

		 RuntimeAnimatorController baseRunContr = manager.Base;
		 if(!avatarComp.baseAnimationLayers[0].isDefault && null != avatarComp.baseAnimationLayers[0].animatorController) {
			baseRunContr = avatarComp.baseAnimationLayers[0].animatorController;
			EditorUtility.SetDirty(baseRunContr);
			AssetDatabase.SaveAssets();
		 }
		 string baseControllerPath = GetPath(false, folderPath, "Base.controller");
		 AssetDatabase.CopyAsset(AssetDatabase.GetAssetPath(baseRunContr), baseControllerPath);
		 AnimatorController baseAnimContr = AssetDatabase.LoadAssetAtPath<AnimatorController>(baseControllerPath);
		 GetBehaviours(baseRunContr, baseAnimContr, layerInfo, VRCAvatarDescriptor.AnimLayerType.Base);
		 CombineAnimator(superAnimator, baseAnimContr, null);
		 layerInfo.data[0].start = 1;
		 layerInfo.data[0].end = layerInfo.data[0].start + baseAnimContr.layers.Length;

		 // Additive
		 AnimatorController additiveAnimContr = null;
		 if(!avatarComp.baseAnimationLayers[1].isDefault && null != avatarComp.baseAnimationLayers[1].animatorController) {
			RuntimeAnimatorController additiveRunContr = avatarComp.baseAnimationLayers[1].animatorController;
			EditorUtility.SetDirty(additiveRunContr);
			AssetDatabase.SaveAssets();
			string additiveControllerPath = GetPath(false, folderPath, "Additive.controller");
			AssetDatabase.CopyAsset(AssetDatabase.GetAssetPath(additiveRunContr), additiveControllerPath);
			additiveAnimContr = AssetDatabase.LoadAssetAtPath<AnimatorController>(additiveControllerPath);
			GetBehaviours(additiveRunContr, additiveAnimContr, layerInfo, VRCAvatarDescriptor.AnimLayerType.Additive);
			CombineAnimator(superAnimator, additiveAnimContr, null);
			layerInfo.data[1].start = layerInfo.data[0].end;
			layerInfo.data[1].end = layerInfo.data[0].end + (additiveAnimContr.layers.Length);
		 } else {
			layerInfo.data[1].start = layerInfo.data[0].end;
			layerInfo.data[1].end = layerInfo.data[0].end;
		 }

		 // TEA Animations
		 CombineAnimator(superAnimator, teaAnimContr, null);

		 // Gesture
		 RuntimeAnimatorController gestureRunContr = manager.Gesture_Male;
		 if(!avatarComp.baseAnimationLayers[2].isDefault && null != avatarComp.baseAnimationLayers[2].animatorController) {
			gestureRunContr = avatarComp.baseAnimationLayers[2].animatorController;
			EditorUtility.SetDirty(gestureRunContr);
			AssetDatabase.SaveAssets();
		 }
		 string gestureControllerPath = GetPath(false, folderPath, "Gesture.controller");
		 AssetDatabase.CopyAsset(AssetDatabase.GetAssetPath(gestureRunContr), gestureControllerPath);
		 AnimatorController gestureAnimContr = AssetDatabase.LoadAssetAtPath<AnimatorController>(gestureControllerPath);
		 GetBehaviours(gestureRunContr, gestureAnimContr, layerInfo, VRCAvatarDescriptor.AnimLayerType.Gesture);
		 CombineAnimator(superAnimator, gestureAnimContr, null);
		 layerInfo.data[2].start = layerInfo.data[1].end + teaAnimContr.layers.Length;
		 layerInfo.data[2].end = layerInfo.data[1].end + teaAnimContr.layers.Length + (gestureAnimContr.layers.Length);

		 //Actions
		 RuntimeAnimatorController actionRunContr = manager.Action;
		 if(!avatarComp.baseAnimationLayers[3].isDefault && null != avatarComp.baseAnimationLayers[3].animatorController) {
			actionRunContr = avatarComp.baseAnimationLayers[3].animatorController;
			EditorUtility.SetDirty(actionRunContr);
			AssetDatabase.SaveAssets();
		 }
		 string actionControllerPath = GetPath(false, folderPath, "Action.controller");
		 AssetDatabase.CopyAsset(AssetDatabase.GetAssetPath(actionRunContr), actionControllerPath);
		 AnimatorController actionAnimContr = AssetDatabase.LoadAssetAtPath<AnimatorController>(actionControllerPath);
		 GetBehaviours(actionRunContr, actionAnimContr, layerInfo, VRCAvatarDescriptor.AnimLayerType.Action);
		 CombineAnimator(superAnimator, actionAnimContr, null);
		 layerInfo.data[3].start = layerInfo.data[2].end;
		 layerInfo.data[3].end = layerInfo.data[2].end + (actionAnimContr.layers.Length);

		 //FX
		 AnimatorController fxAnimContr = null;
		 if(!avatarComp.baseAnimationLayers[4].isDefault && null != avatarComp.baseAnimationLayers[4].animatorController) {
			RuntimeAnimatorController fxRunContr = avatarComp.baseAnimationLayers[4].animatorController;
			EditorUtility.SetDirty(fxRunContr);
			AssetDatabase.SaveAssets();
			string fxControllerPath = GetPath(false, folderPath, "FX.controller");
			AssetDatabase.CopyAsset(AssetDatabase.GetAssetPath(fxRunContr), fxControllerPath);
			fxAnimContr = AssetDatabase.LoadAssetAtPath<AnimatorController>(fxControllerPath);

			GetBehaviours(fxRunContr, fxAnimContr, layerInfo, VRCAvatarDescriptor.AnimLayerType.FX);
			CombineAnimator(superAnimator, fxAnimContr, manager.AvatarMaskNone);
			//SetFXDefault(action, fxAnimContr, avatarComp.gameObject, manager.AvatarMaskNone, folderPath);
			//CombineAnimator(action, fxAnimContr, manager.AvatarMaskNone);
			layerInfo.data[4].start = layerInfo.data[3].end + 1;
			layerInfo.data[4].end = layerInfo.data[3].end + 1 + (fxAnimContr.layers.Length);
		 } else {
			layerInfo.data[4].start = layerInfo.data[3].end;
			layerInfo.data[4].end = layerInfo.data[3].end;
		 }
		 SetAnimationDefault(superAnimator, avatarComp.gameObject, manager.AvatarMaskNone, folderPath);

		 string superAnimatorPath = GetPath(false, folderPath, superAnimator.name + ".controller");
		 AssetDatabase.CreateAsset(superAnimator, superAnimatorPath);
		 manager.Controllers.Add(AssetDatabase.LoadAssetAtPath<RuntimeAnimatorController>(superAnimatorPath));

		 string layerInfoPath = GetPath(false, folderPath, layerInfo.name + ".asset");
		 AssetDatabase.CreateAsset(layerInfo, layerInfoPath);
		 manager.LayerInfo.Add(AssetDatabase.LoadAssetAtPath<TEA_PlayableLayerData>(layerInfoPath));

		 /*Debug.Log($"HEAD[{AvatarController.GetBone(avatarComp, HumanBodyBones.Head).position.ToString("F4")}] "
			+ $"ViewPort:[{avatarComp.ViewPosition.ToString("F4")}] "
			+ $"Avatar:[{avatarComp.gameObject.transform.position.ToString("F4")}] "
			+ $"World from Avatar:[{TEA_EditorUtility.TransformPoint(avatarComp.gameObject.transform, avatarComp.ViewPosition).ToString("F4")}]"
			+ $"calc[{TEA_EditorUtility.InverseTransformPoint(AvatarController.GetBone(avatarComp, HumanBodyBones.Head), TEA_EditorUtility.TransformPoint(avatarComp.gameObject.transform, avatarComp.ViewPosition)).ToString("F4")}]");*/
		 manager.ViewPorts.Add(TEA_EditorUtility.InverseTransformPoint(AvatarController.GetBone(avatarComp, HumanBodyBones.Head), TEA_EditorUtility.TransformPoint(avatarComp.gameObject.transform, avatarComp.ViewPosition)));
		 //Debug.Log($"----- Created animator controllers for [{avatarKey}]");

		 // Validation
		 if(validate) {

			//--- check layers
			string nullLayer = "Playable Layer is not default, it should be set in Descriptor";
			foreach(VRCAvatarDescriptor.CustomAnimLayer layer in avatarComp.baseAnimationLayers) {
			 if(!layer.isDefault && null == layer.animatorController) {
				Issue issue = new TEA_ValidationIssues.Issue(nullLayer, currentAvatar);
				issues.GetLayer(layer.type).Add(issue);
			 }

			 if(settings.LayerRestrictions)
				ValidateOnlyTransforms(layer.type, AssetDatabase.LoadAssetAtPath<AnimatorController>(AssetDatabase.GetAssetPath(layer.animatorController)));
			}

			// missing Expression Parameters
			if(settings.AllParametersUsed)
			 ValidateCustomExpressions(avatarComp, superAnimator);

			// drivers
			if(null == avatar.expressionParameters) {
			 if(drivers.Count > 0)
				issues.ParameterDrivers.Add(new Issue("You have Parameter Drivers but no ExpressionParameters"));
			} else {
			 foreach(DriverIssue driver in drivers) {
				if(driver.driver.parameters.Count == 0) {
				 Issue issue = new TEA_ValidationIssues.Issue($"Layer[{ driver.layerName }]: no parameter set");
				 issue.Reference.Add(driver.state);
				 issue.Reference.Add(driver.driver);
				 issues.GetLayer(driver.layerType).Add(issue);
				}
				foreach(VRCAvatarParameterDriver.Parameter param in driver.driver.parameters) {
				 if(null == currentAvatar.expressionParameters.FindParameter(param.name)) {
					Issue issue = new TEA_ValidationIssues.Issue($"Layer [{driver.layerName}]: [{param.name}] is not in ExpressionParameters");
					issue.Reference.Add(driver.state);
					issue.Reference.Add(driver.driver);
					issues.GetLayer(driver.layerType).Add(issue);
				 }
				 if(!TEA_EditorUtility.HasAnimatorParameter(param.name, superAnimator.parameters)) {
					Issue issue = new TEA_ValidationIssues.Issue($"Layer [{driver.layerName}]: [{param.name}] is not a parameter in any Playable Layer");
					issue.Reference.Add(driver.state);
					issue.Reference.Add(driver.driver);
					issues.GetLayer(driver.layerType).Add(issue);
				 }
				}
			 }//for
			}

			if(issues.ValidationIssues()) {
			 avatarIssues.Add(issues);
			 validationIssue = true;
			}
		 }//validate

		 AssetDatabase.SaveAssets();
		 aCount++;
		}// for avatar

		if(validationIssue) {
		 TEA_Error_Window.Open(avatarIssues);
		}
		return !validationIssue;
	 } catch(TEA_Exception e) {
		throw e;
	 } catch(Exception e) {
		EditorUtility.DisplayDialog(ERROR_HEADER, $"TEA Manager ran into an unexpected issue while compiling [{currentAvatar.name}].\n"
		 + "If you cannot resolve the issue please raise a ticket on the GitHub and include the error log in the console.", "ok");
		Debug.LogError(new TEA_Exception("Unexpected Exception", e));
	 }
	 return false;
	}
Beispiel #8
0
	private static AnimatorController GenerateTEA_Animator(TEA_Manager manager) {
	 // --- TEA  ---
	 AnimatorController teaAnimContr = AssetDatabase.LoadAssetAtPath<AnimatorController>(AssetDatabase.GetAssetPath(manager.TEA_Animations));
	 while(teaAnimContr.layers.Length > 0) {
		teaAnimContr.RemoveLayer(0);
	 }
	 AnimatorStateMachine stateD = new AnimatorStateMachine();
	 teaAnimContr.AddLayer(new AnimatorControllerLayer() {
		name = AvatarController.TEA_HAND_LAYER,
		defaultWeight = 1,
		avatarMask = manager.AvatarMaskArms,
		stateMachine = stateD
	 });

	 //default
	 stateD.defaultState = stateD.AddState("Default");

	 manager.TEA_AnimationClips.ClearOptions();
	 List<Dropdown.OptionData> options = new List<Dropdown.OptionData>();

	 int count = 0;
	 List<AnimationClip> armClips = GetAnimationClips("Assets/TEA Manager/Resources/Animation/TEA Animations/TEA Hand Animations");
	 foreach(AnimationClip clip in armClips) {
		AnimatorState state = stateD.AddState(clip.name);
		state.motion = clip;
		stateD.defaultState.AddTransition(state).AddCondition(AnimatorConditionMode.Equals, count, AvatarController.TEA_ANIM_PARAM);
		state.AddExitTransition().AddCondition(AnimatorConditionMode.NotEqual, count, AvatarController.TEA_ANIM_PARAM);

		Dropdown.OptionData option = new Dropdown.OptionData(clip.name);
		options.Add(option);
		count++;
	 }//for

	 manager.GetComponent<AvatarController>().TEA_HAND_LAYER_COUNT = count;

	 // --- Full Body Animations
	 AnimatorStateMachine stateM = new AnimatorStateMachine();
	 teaAnimContr.AddLayer(new AnimatorControllerLayer() {
		name = AvatarController.TEA_LAYER,
		defaultWeight = 0,
		avatarMask = manager.AvatarMaskAll,
		stateMachine = stateM
	 });

	 stateM.defaultState = stateM.AddState("Default");

	 // dynamic
	 foreach(string folder in AssetDatabase.GetSubFolders("Assets/TEA Manager/Resources/Animation/TEA Animations")) {
		string name = folder.Substring(folder.LastIndexOf('/') + 1);
		if("TEA Hand Animations" == name)
		 continue;
		Dropdown.OptionData option = new Dropdown.OptionData(name);
		options.Add(option);
		AnimationClip start = null;
		AnimationClip loop = null;
		foreach(AnimationClip clip in GetAnimationClips(folder)) {
		 if(clip.name.Contains("intro") || clip.name.Contains("Intro")) {
			start = clip;
		 } else
			loop = clip;
		}//for
		AnimatorState state = stateM.AddState(name);
		state.motion = loop;
		if(null != start) {
		 AnimatorState startState = stateM.AddState(name + "-intro");
		 startState.motion = start;
		 stateM.defaultState.AddTransition(startState).AddCondition(AnimatorConditionMode.Equals, count, AvatarController.TEA_ANIM_PARAM);
		 startState.AddTransition(state).hasExitTime = true;
		} else {
		 stateM.defaultState.AddTransition(state).AddCondition(AnimatorConditionMode.Equals, count, AvatarController.TEA_ANIM_PARAM);
		}
		state.AddExitTransition().AddCondition(AnimatorConditionMode.NotEqual, count, AvatarController.TEA_ANIM_PARAM);
		count++;
	 }//for
	 manager.TEA_AnimationClips.AddOptions(options);
	 AssetDatabase.SaveAssets();
	 return teaAnimContr;
	}