예제 #1
0
        private AnimatorControllerLayer CreateVolumeLayer(string rootName, string paramName, AnimationClip volumeSet)
        {
            AnimatorControllerLayer layer = new AnimatorControllerLayer {
                name          = paramName,
                defaultWeight = 1,
                stateMachine  = new AnimatorStateMachine()
                {
                    name = paramName
                }
            };
            AnimatorStateMachine stateMachine = layer.stateMachine;

            AnimatorState waitState = stateMachine.AddState("Wait");

            AnimatorState toggleState = stateMachine.AddState(paramName);

            toggleState.timeParameter       = paramName;
            toggleState.timeParameterActive = true;
            toggleState.motion = volumeSet;
            waitState.AddTransition(toggleState).AddCondition(AnimatorConditionMode.Greater, 0, paramName);
            Avatar8Track.CreateAsset(AudioClip, volumeSet, paramName + ".anim");

            return(layer);
        }
예제 #2
0
        void OnGUI()
        {
            EditorGUILayout.BeginHorizontal();
            scrollPos = EditorGUILayout.BeginScrollView(scrollPos, GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true));
            if (Stage.Instruction == stage)
            {
                EditorGUILayout.HelpBox("Welcome to Avatar 8Track. This tool let's you automagically turn a folder of songs into a music player in your avatars radial menu.\n"
                                        + "Song Library Setup\n"
                                        + "   - Create a folder somewhere under Assets\n"
                                        + "   - Put all of your songs into that folder\n"
                                        + "        The folder name does not matter.\n"
                                        + "        All songs from the folder will be added\n"
                                        , MessageType.None, true);
                EditorGUILayout.HelpBox("Do not store anything but your songs in the Song Library, it may be deleted", MessageType.Warning, true);
                EditorGUILayout.HelpBox("One song library per avatar!", MessageType.Warning, true);
                EditorGUILayout.HelpBox("If you update the library with new songs just run the tool again", MessageType.Info, true);
                EditorGUILayout.LabelField("", GUI.skin.horizontalSlider);

                // --- Avatar stuff ---
                EditorGUI.BeginChangeCheck();
                avatarIndex = EditorGUILayout.Popup("Avatar", avatarIndex, avatarKeys, EditorStyles.popup);
                if (EditorGUI.EndChangeCheck())
                {
                    expressionParameters = avatars[avatarKeys[avatarIndex]].expressionParameters;
                    expressionsMenu      = avatars[avatarKeys[avatarIndex]].expressionsMenu;
                    _8TrackEditor.SetFromAvatar(avatars[avatarKeys[avatarIndex]]);
                }
                //--- 8Track object
                EditorGUILayout.HelpBox("The 8Track object will hold all of your AudioClip Components."
                                        + "\nIt must be a first child of your avatar."
                                        + "\nThe name of the 8Track object will determine names for various assets."
                                        + "\nI highly recommend you use the default object.", MessageType.Info, true);
                EditorGUILayout.LabelField("The 8Track Object");
                _8TrackEditor._8TrackObject = (GameObject)EditorGUILayout.ObjectField(_8TrackEditor._8TrackObject, typeof(GameObject), true);
                if (null == _8TrackEditor._8TrackObject)
                {
                    _8trackValid = false;
                    if (GUILayout.Button("Create _8Track Object", GUILayout.Height(30)))
                    {
                        _8TrackEditor._8TrackObject = new GameObject("8Track");
                        _8TrackEditor._8TrackObject.transform.parent = _8TrackEditor.Avatar.transform;
                        Debug.Log($"Created new object for tracks [{_8TrackEditor._8TrackObject.name}]");
                    }
                    else
                    {
                        _8TrackEditor.SetFromAvatar(avatars[avatarKeys[avatarIndex]]);
                    }
                }
                else if (_8TrackEditor._8TrackObject.transform.parent != _8TrackEditor.Avatar.transform)
                {
                    EditorGUILayout.HelpBox("The 8Track object must be a child of the avatar selected", MessageType.Error, true);
                    _8trackValid = false;
                }
                else
                {
                    _8trackValid = true;
                }

                //set var
                if (null != _8TrackEditor._8TrackObject)
                {
                    _8TrackEditor.VolumeEPName = Avatar8Track.GetVarName(_8TrackEditor._8TrackObject, Avatar8Track.volumeEPNameSuffix);
                    _8TrackEditor.TrackEPName  = Avatar8Track.GetVarName(_8TrackEditor._8TrackObject, Avatar8Track.trackEPNameSuffix);
                }

                EditorGUILayout.LabelField("", GUI.skin.horizontalSlider);

                //--- Parameters
                if (expressionValid)
                {
                    EditorGUILayout.HelpBox("A Integer and Float parameter will be added", MessageType.Info, true);
                }
                else if (null != expressionParameters)
                {
                    EditorGUILayout.HelpBox("The ExpressionParameters does not have space for a float and an int" + "\nYou can delete empty parameters to make room", MessageType.Error, true);
                    if (GUILayout.Button("Delete Empty Parameters", GUILayout.Height(30)))
                    {
                        for (int i = 0; i < expressionParameters.parameters.Length; i++)
                        {
                            if (string.IsNullOrEmpty(expressionParameters.parameters[i].name))
                            {
                                ArrayUtility.RemoveAt <VRCExpressionParameters.Parameter>(ref expressionParameters.parameters, i);
                                i--;
                            }
                        }
                    }
                }
                else
                {
                    EditorGUILayout.HelpBox("An ExpressionParameters object is required", MessageType.Error, true);
                }

                EditorGUILayout.LabelField("VRC ExpressionParameters File");
                expressionParameters = (VRCExpressionParameters)EditorGUILayout.ObjectField(expressionParameters, typeof(VRCExpressionParameters), true);

                if (null != expressionParameters && null != _8TrackEditor._8TrackObject)
                {
                    int cost = VRCExpressionParameters.TypeCost(VRCExpressionParameters.ValueType.Int) + VRCExpressionParameters.TypeCost(VRCExpressionParameters.ValueType.Float);
                    VRCExpressionParameters.Parameter[] parameters = expressionParameters.parameters;
                    foreach (VRCExpressionParameters.Parameter parameter in parameters)
                    {
                        if (parameter.name == _8TrackEditor.VolumeEPName)
                        {
                            cost -= VRCExpressionParameters.TypeCost(VRCExpressionParameters.ValueType.Float);
                        }
                        else if (parameter.name == _8TrackEditor.TrackEPName)
                        {
                            cost -= VRCExpressionParameters.TypeCost(VRCExpressionParameters.ValueType.Int);
                        }
                    }
                    expressionValid = expressionParameters.CalcTotalCost() + cost <= VRCExpressionParameters.MAX_PARAMETER_COST;
                }
                else
                {
                    expressionValid = null != expressionParameters;
                }
                EditorGUILayout.LabelField("", GUI.skin.horizontalSlider);

                //--- Menu
                if (menuValid)
                {
                    EditorGUILayout.HelpBox("Which VRCExpressionsMenu do you want the SubMenu added to", MessageType.Info, true);
                }
                else if (null != expressionsMenu)
                {
                    EditorGUILayout.HelpBox("The VRCExpressionsMenu is full", MessageType.Error, true);
                }

                if (null == expressionsMenu)
                {
                    EditorGUILayout.HelpBox("ExpressionsMenu is not set", MessageType.Warning, true);
                }

                EditorGUILayout.LabelField("VRC Expressions Menu File");
                expressionsMenu = (VRCExpressionsMenu)EditorGUILayout.ObjectField(expressionsMenu, typeof(VRCExpressionsMenu), true);

                if (null != expressionsMenu && null != _8TrackEditor._8TrackObject)
                {
                    menuValid = expressionsMenu.controls.Count < VRCExpressionsMenu.MAX_CONTROLS;
                    foreach (VRCExpressionsMenu.Control control in expressionsMenu.controls)
                    {
                        if (control.name == _8TrackEditor._8TrackObject.name)
                        {
                            menuValid = true;
                        }
                    }
                }
                else
                {
                    menuValid = true;
                }


                if (null != expressionParameters && menuValid && expressionValid && _8trackValid)
                {
                    Button(Stage._8Track, "Setup");
                }
            }
            else if (Stage._8Track == stage)
            {
                _8TrackEditor.OnGUI();
                Button(Stage.Instruction, "Back <-");
                if (_8TrackEditor.IsValid())
                {
                    Button(Stage.Burn, "Continue ->");
                }
            }

            if (Stage.Burn == stage)
            {
                EditorGUILayout.HelpBox("Read Carefully!!!!!!", MessageType.Error);
                EditorGUILayout.HelpBox("This will break the 8Track functionality for any other avatar this song library has been added to previously."
                                        + "\nDuplicate the song library if you want to add it to a separate avatar.", MessageType.Warning);
                EditorGUILayout.HelpBox("Avatar 8Tracks lets you update your song library by re-running it on the same avatar."
                                        + "\nfor convenience it auto-detects and deletes assets it has created previously and replaces them."
                                        + "\nDouble check the following items below were not manually edited by you."
                                        , MessageType.Warning);
                EditorGUILayout.LabelField("FX Controller Layers, Expression Parameters, and Expression Menu Controls with the following names", EditorStyles.wordWrappedLabel);
                EditorGUILayout.LabelField($"     [{_8TrackEditor.TrackEPName}]", EditorStyles.boldLabel);
                EditorGUILayout.LabelField($"     [{_8TrackEditor.VolumeEPName}]", EditorStyles.boldLabel);
                EditorGUILayout.LabelField($"     [{_8TrackEditor._8TrackObject.name}]", EditorStyles.boldLabel);
                EditorGUILayout.HelpBox($"All AnimationClips, and ExpressionsMenus will be deleted in [{GetAssetDirectory(_8TrackEditor.AudioClip, true)}]", MessageType.Warning);
                Button(Stage._8Track, "Back <-");
                if (GUILayout.Button("Accept And Burn Tracks", GUILayout.Height(30)))
                {
                    try {
                        string songLibrary = GetAssetDirectory(_8TrackEditor.AudioClip, false);
                        CleanSongLibrary(songLibrary);
                        List <AudioClip> libAssets = GetSongList(songLibrary);
                        _8TrackEditor.BurnTracks(libAssets);
                        VRC_Actions(songLibrary, libAssets, _8TrackEditor);
                        AssetDatabase.SaveAssets();
                        EditorUtility.DisplayDialog("Avatar 8Tracks", "You're ready to rock", "great");
                        this.Close();
                    } catch (System.Exception e) {
                        EditorUtility.DisplayDialog("so... this happened", e.Message, "sorry");
                        Debug.LogException(e);
                        this.Close();
                    }
                }
                DrawEnd();
            }
            else
            {
                DrawEnd();
            }
        }
예제 #3
0
        public bool BurnTracks(List <AudioClip> libAssets)
        {
            if (null == fxAnimator)
            {
                throw new System.Exception("We need your FX Animator Controller");
            }
            if (null == AudioClip)
            {
                throw new System.Exception("We need an AudioClip from your Song Library");
            }
            if (null == _8TrackObject)
            {
                throw new System.Exception("8Track object was not set");
            }
            _8TrackObject.SetActive(false);

            int childIndex = 0;

            while (true)
            {
                if (0 == _8TrackObject.transform.childCount || childIndex >= _8TrackObject.transform.childCount)
                {
                    break;
                }
                else if (_8TrackObject.transform.GetChild(childIndex).gameObject.name.StartsWith("Track"))
                {
                    Debug.Log("deleting child " + _8TrackObject.transform.GetChild(childIndex).gameObject.name);
                    DestroyImmediate(_8TrackObject.transform.GetChild(childIndex).gameObject);
                }
                else
                {
                    childIndex++;
                }
            }

            RemoveExistingAnimatorLayer(fxAnimator, _8TrackObject.name);
            HandleAnimatorParameters(fxAnimator, _8TrackObject.name);

            //--- --- Volume Animation Controller --- ---
            AnimationClip volumeSet = new AnimationClip {
                name = VolumeEPName
            };

            //--- --- Track Animation Controller --- ---
            AnimatorControllerLayer trackLayer = new AnimatorControllerLayer {
                name          = _8TrackObject.name,
                defaultWeight = 1,
                stateMachine  = new AnimatorStateMachine()
                {
                    name = _8TrackObject.name
                }
            };

            fxAnimator.AddLayer(trackLayer);
            AnimatorStateMachine stateMachine = trackLayer.stateMachine;

            //--- --- No Track --- ---
            int           trackCount   = 0;
            AnimatorState defaultState = stateMachine.AddState("Stop");

            defaultState.speed = 100;
            AnimatorStateTransition anyToWait = stateMachine.AddAnyStateTransition(defaultState);

            anyToWait.AddCondition(AnimatorConditionMode.Equals, trackCount, TrackEPName);
            anyToWait.hasExitTime = true;
            anyToWait.exitTime    = 0;
            anyToWait.duration    = 0;

            AnimatorState loopState = stateMachine.AddState("LoopOff");

            loopState.speed = 100;
            if (!PlayerLoops)
            {
                PersistAnimator(fxAnimator);
                VRCAvatarParameterDriver driver = loopState.AddStateMachineBehaviour <VRCAvatarParameterDriver>();
                driver.parameters.Add(new VRC.SDKBase.VRC_AvatarParameterDriver.Parameter()
                {
                    name  = TrackEPName,
                    value = 0,
                    type  = VRC.SDKBase.VRC_AvatarParameterDriver.ChangeType.Set
                });
            }
            AnimatorStateTransition loopExit = loopState.AddExitTransition();

            loopExit.hasExitTime = true;
            loopExit.exitTime    = 0;
            loopExit.duration    = 0;

            //--- --- All Tracks --- ---
            foreach (Object asset in libAssets)
            {
                if (asset is AudioClip)
                {
                    //Animation setup
                    string trackName = "Track " + ++trackCount;

                    AnimationClip tracktoggle = new AnimationClip {
                        name = trackName
                    };

                    AudioClip clip = asset as AudioClip;

                    tracktoggle.SetCurve(_8TrackObject.name, typeof(GameObject), "m_IsActive", AnimationCurve.Linear(0.0f, 1f, clip.length, 1f));
                    tracktoggle.SetCurve(_8TrackObject.name + "/" + trackName, typeof(GameObject), "m_IsActive", AnimationCurve.Linear(0.0f, 1f, clip.length, 1f));
                    AnimatorState state = stateMachine.AddState(trackName);
                    state.motion = tracktoggle;
                    AnimatorStateTransition toTrack = defaultState.AddTransition(state);
                    toTrack.AddCondition(AnimatorConditionMode.Equals, trackCount, TrackEPName);
                    toTrack.hasExitTime = true;
                    toTrack.exitTime    = 0;
                    toTrack.duration    = 0;
                    AnimatorStateTransition trackOut = state.AddTransition(loopState);
                    trackOut.hasExitTime = true;
                    trackOut.exitTime    = 1;
                    trackOut.duration    = 0;
                    AnimatorStateTransition trackSwitch = state.AddTransition(defaultState);
                    trackSwitch.AddCondition(AnimatorConditionMode.NotEqual, trackCount, TrackEPName);
                    trackSwitch.duration = 0;
                    Avatar8Track.CreateAsset(AudioClip, tracktoggle, trackName + ".anim");

                    //volume
                    volumeSet.SetCurve(_8TrackObject.name + "/" + trackName, typeof(AudioSource), "m_Volume", AnimationCurve.Linear(0.0f, 0f, 0.033333335f, 1f));

                    //Object setup
                    GameObject trackObject = new GameObject(trackName, new System.Type[] { typeof(AudioSource) });
                    trackObject.transform.SetParent(_8TrackObject.transform);
                    trackObject.SetActive(false);
                    //trackObject.AddComponent<AudioSource>();
                    Avatar8Track.CopyComponent(_8TrackObject.GetComponent <AudioSource>(), trackObject.GetComponent <AudioSource>());
                    AudioSource source = trackObject.GetComponent <AudioSource>();
                    source.enabled   = true;
                    source.clip      = clip;
                    trackObject.name = trackName;
                }
            }

            fxAnimator.AddLayer(CreateVolumeLayer(_8TrackObject.name, VolumeEPName, volumeSet));
            PersistAnimator(fxAnimator);

            return(true);
        }