private void AddParameter()
    {
        for (int i = 0; i < expressionParams.parameters.Length; i++)
        {
            if (expressionParams.parameters[i].name == "ToggleMarker" ||
                expressionParams.parameters[i].name.Trim().Length == 0)
            {
                expressionParams.parameters[i].name      = "ToggleMarker";
                expressionParams.parameters[i].valueType = VRCExpressionParameters.ValueType.Bool;
                EditorUtility.SetDirty(expressionParams);
                return;
            }
        }
        int size = GetParameterSize();

        if (size < 128)
        {
            int n = expressionParams.parameters.Length;
            VRCExpressionParameters.Parameter[] newParams = new VRCExpressionParameters.Parameter[n + 1];
            for (int i = 0; i < n; i++)
            {
                newParams[i] = expressionParams.parameters[i];
            }
            newParams[n]                = new VRCExpressionParameters.Parameter();
            newParams[n].name           = "ToggleMarker";
            newParams[n].valueType      = VRCExpressionParameters.ValueType.Bool;
            expressionParams.parameters = newParams;
            EditorUtility.SetDirty(expressionParams);
            return;
        }
        Debug.LogError("Could not create Avatar 3.0 parameter. You may be out of paramters, try creating it manually.");
        return;
    }
示例#2
0
        private static int GetParamIndex(string paramName)
        {
            VRCExpressionParameters.Parameter[] parameters = new VRCExpressionParameters.Parameter[0];

            if (VRCPlayer
                .field_Internal_Static_VRCPlayer_0?.prop_VRCAvatarManager_0?.prop_VRCAvatarDescriptor_0?.expressionParameters?.parameters != null)
            {
                parameters = VRCPlayer
                             .field_Internal_Static_VRCPlayer_0
                             .prop_VRCAvatarManager_0.prop_VRCAvatarDescriptor_0.expressionParameters
                             .parameters;
            }
            else
            {
                return(-1);
            }

            var index = -1;

            for (var i = 0; i < parameters.Length; i++)
            {
                VRCExpressionParameters.Parameter param = parameters[i];
                if (param.name == null)
                {
                    return(-1);
                }
                if (param.name == paramName)
                {
                    index = i;
                }
            }

            return(index);
        }
        public static bool GetBoolParameter(string paramName)
        {
            if (AnimatorParameters != null && !string.IsNullOrEmpty(paramName))
            {
                foreach (var animatorParameter in AnimatorParameters)
                {
                    VRCExpressionParameters.Parameter expressionParameter = animatorParameter.field_Public_Parameter_0;
                    if (expressionParameter.name == paramName && expressionParameter.valueType == VRCExpressionParameters.ValueType.Bool)
                    {
                        return(animatorParameter?.field_Public_AvatarParameter_0?.prop_Boolean_0 ?? false);
                    }
                }
            }

            return(false);
        }
        public static int GetIntParameter(string paramName)
        {
            if (AnimatorParameters != null && !string.IsNullOrEmpty(paramName))
            {
                foreach (var animatorParameter in AnimatorParameters)
                {
                    VRCExpressionParameters.Parameter expressionParameter = animatorParameter.field_Public_Parameter_0;
                    if (expressionParameter.name == paramName && expressionParameter.valueType == VRCExpressionParameters.ValueType.Int)
                    {
                        return(animatorParameter?.field_Public_AvatarParameter_0?.prop_Int32_0 ?? 0);
                    }
                }
            }

            return(0);
        }
示例#5
0
        public static bool AddBitKeys(VRCExpressionParameters parameters)
        {
            List <VRCExpressionParameters.Parameter> paramList = parameters.parameters.ToList();

            for (int i = 0; i < KeyCount; ++i)
            {
                string bitKeyName = $"BitKey{i}";

                int index = Array.FindIndex(parameters.parameters, p => p.name == bitKeyName);
                if (index != -1)
                {
                    Debug.Log($"Found BitKey in params {bitKeyName}");
                    parameters.parameters[index].saved        = true;
                    parameters.parameters[index].defaultValue = 0;
                    parameters.parameters[index].valueType    = VRCExpressionParameters.ValueType.Bool;
                }
                else
                {
                    Debug.Log($"Adding BitKey in params {bitKeyName}");
                    var newParam = new VRCExpressionParameters.Parameter
                    {
                        name         = bitKeyName,
                        saved        = true,
                        defaultValue = 0,
                        valueType    = VRCExpressionParameters.ValueType.Bool
                    };
                    paramList.Add(newParam);
                }
            }

            parameters.parameters = paramList.ToArray();

            int remainingCost = VRCExpressionParameters.MAX_PARAMETER_COST - parameters.CalcTotalCost();;

            Debug.Log(remainingCost);
            if (remainingCost < 0)
            {
                Debug.LogError("Adding BitKeys took up too many parameters!");
                EditorUtility.DisplayDialog("Adding BitKeys took up too many parameters!", "Go to your VRCExpressionParameters and remove some unnecessary parameters to make room for the 32 BitKey bools and run this again.", "Okay");
                return(false);
            }

            EditorUtility.SetDirty(parameters);

            return(true);
        }
示例#6
0
        private ParameterValueType GetParameterType(VRCExpressionParameters.Parameter parameter)
        {
            switch (parameter.valueType)
            {
            case VRCExpressionParameters.ValueType.Float:
                return(ParameterValueType.Float);

            case VRCExpressionParameters.ValueType.Int:
                return(ParameterValueType.Int);

            case VRCExpressionParameters.ValueType.Bool:
                return(ParameterValueType.Bool);

            default:
                throw new ArgumentOutOfRangeException();
            }
        }
    public override void Build(MenuActions.MenuAction parent)
    {
        var controller = GetController(AnimationLayer.FX);

        //Define volume param
        {
            var param = new VRCExpressionParameters.Parameter();
            param.name         = parameter;
            param.valueType    = VRCExpressionParameters.ValueType.Float;
            param.defaultValue = 0;
            param.saved        = false;
            DefineExpressionParameter(param);
        }

        //Define parameters on controller
        AddParameter(controller, "Viseme", AnimatorControllerParameterType.Int, 0);
        AddParameter(controller, parameter, AnimatorControllerParameterType.Float, 0);

        BuildDriverLayer();
        BuildAnimationLayer();
    }
 private static void ParameterFixes(VRCExpressionParameters.Parameter param, VRCExpressionParameters expressionParameters, JustHaiToggleGroup @group)
 {
     if (param == null)
     {
         EditorGUILayout.HelpBox("Expression Parameter does not exist", MessageType.Error);
         if (GUILayout.Button("Fix: Create Expression Parameter"))
         {
             var newParameters = new VRCExpressionParameters.Parameter[expressionParameters.parameters.Length + 1];
             expressionParameters.parameters.CopyTo(newParameters, 0);
             expressionParameters.parameters = newParameters;
             expressionParameters.parameters[expressionParameters.parameters.Length - 1] = new VRCExpressionParameters.Parameter()
             {
                 name         = @group.parameterName,
                 defaultValue = @group.hintEnabled ? 1f : 0f,
                 saved        = true,
                 valueType    = VRCExpressionParameters.ValueType.Bool
             };
             ForceSaveAsset(expressionParameters);
         }
     }
     else if (param.valueType != VRCExpressionParameters.ValueType.Bool)
     {
         EditorGUILayout.HelpBox($"Expression Parameter exists but it is not a Bool (currently: {param.valueType})", MessageType.Error);
         if (GUILayout.Button("Fix: Change Expression Parameter Type to Bool"))
         {
             param.valueType    = VRCExpressionParameters.ValueType.Bool;
             param.defaultValue = @group.hintEnabled ? 1f : 0f;
             ForceSaveAsset(expressionParameters);
         }
     }
     else if (param.defaultValue != (@group.hintEnabled ? 1f : 0f))
     {
         EditorGUILayout.HelpBox($"Expression Parameter default value is not the same", MessageType.Warning);
         if (GUILayout.Button("Fix: Change Expression Parameter Default Value"))
         {
             param.defaultValue = @group.hintEnabled ? 1f : 0f;
             ForceSaveAsset(expressionParameters);
         }
     }
 }
        public static VRCExpressionParameters.Parameter AddVRCExpressionsParameter(VRCAvatarDescriptor avatarDescriptor, VRCExpressionParameters.ValueType type, string name, List <Object> dirtyAssets)
        {
            VRCExpressionParameters parameters = avatarDescriptor.expressionParameters;

            VRCExpressionParameters.Parameter parameter = parameters.FindParameter(name);

            if (parameter == null)
            {
                var list = parameters.parameters.Where(e => e != null && !string.IsNullOrEmpty(e.name)).ToList();
                parameter = new VRCExpressionParameters.Parameter
                {
                    name      = name,
                    valueType = type,
                };
                list.Add(parameter);
                parameters.parameters = list.ToArray();
            }

            dirtyAssets.Add(parameters);
            dirtyAssets.Add(avatarDescriptor.gameObject);
            return(parameter);
        }
        public static bool Add(this VRCExpressionParameters parameters, VRCExpressionParameters.Parameter parameter)
        {
            var emptyFirstIndex = 0;

            for (var i = 0; i < parameters.parameters.Length; i++)
            {
                if (!string.IsNullOrEmpty(parameters.parameters[i].name))
                {
                    continue;
                }
                emptyFirstIndex = i;
                break;
            }

            if (emptyFirstIndex == parameters.parameters.Length)
            {
                return(false);
            }

            parameters.parameters[emptyFirstIndex] = parameter;

            return(true);
        }
示例#11
0
        public static void AddParameter(this VRCExpressionParameters source, VRCExpressionParameters.Parameter parameter)
        {
            var so = new SerializedObject(source);

            so.Update();

            var sourceParameters = so.FindProperty(nameof(source.parameters));

            sourceParameters.arraySize += 1;

            var idx = sourceParameters.arraySize - 1;

            sourceParameters.InsertArrayElementAtIndex(idx);

            var obj = sourceParameters.GetArrayElementAtIndex(idx);

            obj.FindPropertyRelative("name").stringValue        = parameter.name;
            obj.FindPropertyRelative("valueType").intValue      = (int)parameter.valueType;
            obj.FindPropertyRelative("defaultValue").floatValue = parameter.defaultValue;
            obj.FindPropertyRelative("saved").boolValue         = parameter.saved;

            so.ApplyModifiedProperties();
        }
 public static Vrc3Param CreateParamFromNothing(VRCExpressionParameters.Parameter parameter)
 {
     return(new Vrc3ParamExternal(parameter.name, ModuleVrc3Styles.Data.TypeOf[parameter.valueType]));
 }
示例#13
0
 public VrcParameterDefinition Create(AvatarDefinition parent, VRCExpressionParameters.Parameter parameter)
 {
     return(Create(parent, parameter.name, GetParameterType(parameter)));
 }
        /// <summary>
        /// Creates a copy of the avatar descriptor's parameter asset or creates one if it doesn't exist, adds a provided parameter,
        /// assigns the new parameter asset, and stores it in the specified directory.
        /// </summary>
        /// <param name="descriptor">The avatar descriptor to add the parameter to.</param>
        /// <param name="parameter">The parameter to add.</param>
        /// <param name="directory">The unique directory to store the new parameter asset, ex. "Assets/MyCoolScript/GeneratedAssets/725638/".</param>
        /// <param name="overwrite">Optionally, choose to not overwrite an asset of the same name in directory. See class for more info.</param>
        public static void AddParameter(VRCAvatarDescriptor descriptor, VRCExpressionParameters.Parameter parameter, string directory, bool overwrite = true)
        {
            if (descriptor == null)
            {
                Debug.LogError("Couldn't add the parameter, the avatar descriptor is null!");
                return;
            }
            else if ((parameter == null) || (parameter.name == null))
            {
                Debug.LogError("Couldn't add the parameter, it or its name is null!");
                return;
            }
            else if ((directory == null) || (directory == ""))
            {
                Debug.Log("Directory was not specified, storing new parameters asset in " + defaultDirectory);
                directory = defaultDirectory;
            }

            descriptor.customExpressions = true;
            VRCExpressionParameters parameters = ScriptableObject.CreateInstance <VRCExpressionParameters>();

            parameters.parameters = new VRCExpressionParameters.Parameter[0];

            if (descriptor.expressionParameters == null)
            {
                AssetDatabase.CreateAsset(parameters, directory + "Parameters.asset");
            }
            else
            {
                if ((descriptor.expressionParameters.CalcTotalCost() + VRCExpressionParameters.TypeCost(parameter.valueType)) > VRCExpressionParameters.MAX_PARAMETER_COST)
                {
                    Debug.LogError("Couldn't add parameter '" + parameter.name + "', not enough memory free in the avatar's parameter asset!");
                    return;
                }

                string path = (directory + descriptor.expressionParameters.name + ".asset");
                path = (overwrite) ? path : AssetDatabase.GenerateUniqueAssetPath(path);
                if (AssetDatabase.GetAssetPath(descriptor.expressionParameters) != path) // if we have not made a copy yet
                {                                                                        // CopyAsset with two identical strings yields exception
                    AssetDatabase.CopyAsset(AssetDatabase.GetAssetPath(descriptor.expressionParameters), path);
                }
                parameters = AssetDatabase.LoadAssetAtPath(path, typeof(VRCExpressionParameters)) as VRCExpressionParameters;
            }

            if (parameters.FindParameter(parameter.name) == null)
            {
                int count = parameters.parameters.Length;
                VRCExpressionParameters.Parameter[] parameterArray = new VRCExpressionParameters.Parameter[count + 1];
                for (int i = 0; i < count; i++)
                {
                    parameterArray[i] = parameters.GetParameter(i);
                }
                parameterArray[count] = parameter;
                parameters.parameters = parameterArray;
            }

            EditorUtility.SetDirty(parameters);
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
            descriptor.expressionParameters = parameters;
        }
示例#15
0
        public void Generate()
        {
            // Unique directory setup, named after avatar
            Directory.CreateDirectory("Assets/VRLabs/GeneratedAssets/Marker/");
            AssetDatabase.Refresh();
            // Folder name cannot contain these chars
            string cleanedName = string.Join("", descriptor.name.Split('/', '?', '<', '>', '\\', ':', '*', '|', '\"'));
            string guid        = AssetDatabase.CreateFolder("Assets/VRLabs/GeneratedAssets/Marker", cleanedName);
            string directory   = AssetDatabase.GUIDToAssetPath(guid) + "/";

            // Install layers, parameters, and menu before prefab setup
            // FX layer
            if (useIndexFinger)
            {
                AssetDatabase.CopyAsset("Assets/VRLabs/Marker/Resources/M_FX (Finger).controller", directory + "FXtemp.controller");
            }
            else
            {
                AssetDatabase.CopyAsset("Assets/VRLabs/Marker/Resources/M_FX.controller", directory + "FXtemp.controller");
            }
            AnimatorController FX = AssetDatabase.LoadAssetAtPath(directory + "FXtemp.controller", typeof(AnimatorController)) as AnimatorController;

            // remove controller layers before merging to avatar, corresponding to setup
            if (leftHanded)
            {
                RemoveLayer(FX, "M_Marker R");
            }
            else
            {
                RemoveLayer(FX, "M_Marker L");
            }

            if (!brushSize)
            {
                RemoveLayer(FX, "M_Size");
                RemoveParameter(FX, "M_Size");
            }

            if (!eraserSize)
            {
                RemoveLayer(FX, "M_EraserSize");
                RemoveParameter(FX, "M_EraserSize");
            }

            if (!localSpace)
            {
                RemoveLayer(FX, "M_Space");
                RemoveParameter(FX, "M_Space");
                RemoveLayer(FX, "M_Cull");
            }
            else
            {
                RemoveLayer(FX, "M_SpaceSimple");
                RemoveParameter(FX, "M_SpaceSimple");
                RemoveLayer(FX, "M_CullSimple");
            }

            if (writeDefaults)
            {
                AV3ManagerFunctions.SetWriteDefaults(FX);
            }
            if (gestureToDraw != 3)             // uses fingerpoint by default
            {
                ChangeGestureCondition(FX, 0, gestureToDraw);
            }

            // Set parameter driver on 'Clear' state to reset local space
            AnimatorState            state  = FX.layers[0].stateMachine.states.FirstOrDefault(s => s.state.name.Equals("Clear")).state;
            VRCAvatarParameterDriver driver = (VRCAvatarParameterDriver)state.behaviours[0];
            string driverParamName          = localSpace ? "M_Space" : "M_SpaceSimple";

            VRC.SDKBase.VRC_AvatarParameterDriver.Parameter param = new VRC.SDKBase.VRC_AvatarParameterDriver.Parameter()
            {
                name  = driverParamName,
                type  = VRC.SDKBase.VRC_AvatarParameterDriver.ChangeType.Set,
                value = 0f
            };
            driver.parameters.Add(param);

            EditorUtility.SetDirty(FX);
            AV3ManagerFunctions.MergeToLayer(descriptor, FX, AV3ManagerFunctions.PlayableLayer.FX, directory);
            AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(FX));             // delete temporary FX layer

            // Gesture layer
            AssetDatabase.CopyAsset("Assets/VRLabs/Marker/Resources/M_Gesture.controller", directory + "gestureTemp.controller");             // to modify
            AnimatorController gesture = AssetDatabase.LoadAssetAtPath(directory + "gestureTemp.controller", typeof(AnimatorController)) as AnimatorController;

            if (descriptor.baseAnimationLayers[2].isDefault == true || descriptor.baseAnimationLayers[2].animatorController == null)
            {
                AssetDatabase.CopyAsset(path_defaultGesture, directory + "Gesture.controller");
                AnimatorController gestureOriginal = AssetDatabase.LoadAssetAtPath(directory + "Gesture.controller", typeof(AnimatorController)) as AnimatorController;

                descriptor.customExpressions = true;
                descriptor.baseAnimationLayers[2].isDefault          = false;
                descriptor.baseAnimationLayers[2].animatorController = gestureOriginal;

                if (writeDefaults)
                {
                    AV3ManagerFunctions.SetWriteDefaults(gestureOriginal);
                    EditorUtility.SetDirty(gestureOriginal);
                }
            }

            gesture.RemoveLayer((leftHanded) ? 1 : 0);
            if (useIndexFinger)
            {               // use different hand animations
                for (int i = 0; i < 3; i++)
                {
                    if (gesture.layers[0].stateMachine.states[i].state.motion.name == "M_Gesture")
                    {
                        gesture.layers[0].stateMachine.states[i].state.motion = AssetDatabase.LoadAssetAtPath("Assets/VRLabs/Marker/Resources/Animations/Gesture/M_Gesture (Finger).anim", typeof(AnimationClip)) as AnimationClip;
                    }
                    else if (gesture.layers[0].stateMachine.states[i].state.motion.name == "M_Gesture Draw")
                    {
                        gesture.layers[0].stateMachine.states[i].state.motion = AssetDatabase.LoadAssetAtPath("Assets/VRLabs/Marker/Resources/Animations/Gesture/M_Gesture Draw (Finger).anim", typeof(AnimationClip)) as AnimationClip;
                    }
                }
            }
            if (gestureToDraw != 3)
            {
                ChangeGestureCondition(gesture, 0, gestureToDraw);
            }
            if (writeDefaults)
            {
                AV3ManagerFunctions.SetWriteDefaults(gesture, true);
            }

            EditorUtility.SetDirty(gesture);
            AV3ManagerFunctions.MergeToLayer(descriptor, gesture, AV3ManagerFunctions.PlayableLayer.Gesture, directory);
            AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(gesture));             // delete temporary gesture layer

            // layer weight control from merged layer may need index set correctly
            AnimatorController avatarGesture = (AnimatorController)descriptor.baseAnimationLayers[2].animatorController;

            for (int i = 0; i < avatarGesture.layers.Length; i++)
            {               // the controls' layer is normally 3 (AllParts, LeftHand, RightHand, >>>M_Gesture<<<)
                if (avatarGesture.layers[i].name.Contains("M_Gesture") && (i != 3))
                {
                    for (int j = 0; j < 3; j++)
                    {
                        if (avatarGesture.layers[i].stateMachine.states[j].state.behaviours.Length != 0)
                        {
                            VRCAnimatorLayerControl ctrl = (VRCAnimatorLayerControl)avatarGesture.layers[i].stateMachine.states[j].state.behaviours[0];
                            ctrl.layer = i;
                        }
                    }
                }
            }

            EditorUtility.SetDirty(avatarGesture);

            // Parameters
            VRCExpressionParameters.Parameter
                p_marker = new VRCExpressionParameters.Parameter
            {
                name = "M_Marker", valueType = VRCExpressionParameters.ValueType.Bool, saved = false
            },
                p_eraser = new VRCExpressionParameters.Parameter
            {
                name = "M_Eraser", valueType = VRCExpressionParameters.ValueType.Bool, saved = false
            },
                p_clear = new VRCExpressionParameters.Parameter
            {
                name = "M_Clear", valueType = VRCExpressionParameters.ValueType.Bool, saved = false
            },
                p_color = new VRCExpressionParameters.Parameter
            {
                name = "M_Color", valueType = VRCExpressionParameters.ValueType.Float, saved = true
            };
            AV3ManagerFunctions.AddParameter(descriptor, p_marker, directory);
            AV3ManagerFunctions.AddParameter(descriptor, p_eraser, directory);
            AV3ManagerFunctions.AddParameter(descriptor, p_clear, directory);
            AV3ManagerFunctions.AddParameter(descriptor, p_color, directory);

            if (localSpace)
            {
                VRCExpressionParameters.Parameter p_space = new VRCExpressionParameters.Parameter
                {
                    name = "M_Space", valueType = VRCExpressionParameters.ValueType.Int, saved = false
                };
                AV3ManagerFunctions.AddParameter(descriptor, p_space, directory);
            }
            else
            {
                VRCExpressionParameters.Parameter p_spaceSimple = new VRCExpressionParameters.Parameter
                {
                    name = "M_SpaceSimple", valueType = VRCExpressionParameters.ValueType.Bool, saved = false
                };
                AV3ManagerFunctions.AddParameter(descriptor, p_spaceSimple, directory);
            }

            if (brushSize)
            {
                VRCExpressionParameters.Parameter p_size = new VRCExpressionParameters.Parameter
                {
                    name = "M_Size", valueType = VRCExpressionParameters.ValueType.Float, saved = false
                };
                AV3ManagerFunctions.AddParameter(descriptor, p_size, directory);
            }
            if (eraserSize)
            {
                VRCExpressionParameters.Parameter p_eraserSize = new VRCExpressionParameters.Parameter
                {
                    name = "M_EraserSize", valueType = VRCExpressionParameters.ValueType.Float, saved = false
                };
                AV3ManagerFunctions.AddParameter(descriptor, p_eraserSize, directory);
            }

            VRCExpressionParameters.Parameter p_menu = new VRCExpressionParameters.Parameter
            {
                name = "M_Menu", valueType = VRCExpressionParameters.ValueType.Bool, saved = false
            };
            AV3ManagerFunctions.AddParameter(descriptor, p_menu, directory);

            // handle menu instancing
            AssetDatabase.CopyAsset("Assets/VRLabs/Marker/Resources/M_Menu.asset", directory + "Marker Menu.asset");
            VRCExpressionsMenu markerMenu = AssetDatabase.LoadAssetAtPath(directory + "Marker Menu.asset", typeof(VRCExpressionsMenu)) as VRCExpressionsMenu;

            if (!localSpace)             // change from submenu to 1 toggle
            {
                VRCExpressionsMenu.Control.Parameter pm_spaceSimple = new VRCExpressionsMenu.Control.Parameter
                {
                    name = "M_SpaceSimple"
                };
                markerMenu.controls[6].type      = VRCExpressionsMenu.Control.ControlType.Toggle;
                markerMenu.controls[6].parameter = pm_spaceSimple;
                markerMenu.controls[6].subMenu   = null;               // or else the submenu is still there internally, SDK complains
            }
            else
            {
                AssetDatabase.CopyAsset("Assets/VRLabs/Marker/Resources/M_Menu Space.asset", directory + "Marker Space Submenu.asset");
                VRCExpressionsMenu subMenu = AssetDatabase.LoadAssetAtPath(directory + "Marker Space Submenu.asset", typeof(VRCExpressionsMenu)) as VRCExpressionsMenu;

                if (localSpaceFullBody == 0)                 // remove left and right foot controls
                {
                    subMenu.controls.RemoveAt(7);
                    subMenu.controls.RemoveAt(6);
                }
                markerMenu.controls[6].subMenu = subMenu;
                EditorUtility.SetDirty(subMenu);
            }

            if (!brushSize)
            {
                RemoveMenuControl(markerMenu, "Brush Size");
            }

            if (!eraserSize)
            {
                RemoveMenuControl(markerMenu, "Eraser Size");
            }

            EditorUtility.SetDirty(markerMenu);

            VRCExpressionsMenu.Control.Parameter pm_menu = new VRCExpressionsMenu.Control.Parameter
            {
                name = "M_Menu"
            };
            Texture2D markerIcon = AssetDatabase.LoadAssetAtPath("Assets/VRLabs/Marker/Resources/Icons/M_Icon_Menu.png", typeof(Texture2D)) as Texture2D;

            AV3ManagerFunctions.AddSubMenu(descriptor, markerMenu, "Marker", directory, pm_menu, markerIcon);

            // setup in scene
            GameObject marker = PrefabUtility.InstantiatePrefab(AssetDatabase.LoadAssetAtPath("Assets/VRLabs/Marker/Resources/Marker.prefab", typeof(GameObject))) as GameObject;

            if (PrefabUtility.IsPartOfPrefabInstance(marker))
            {
                PrefabUtility.UnpackPrefabInstance(marker, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction);
            }
            marker.transform.SetParent(avatar.transform, false);

            Transform system       = marker.transform.Find("System");
            Transform targets      = marker.transform.Find("Targets");
            Transform markerTarget = targets.Find("MarkerTarget");
            Transform markerModel  = targets.Find("Model");
            Transform eraser       = system.Find("Eraser");
            Transform local        = marker.transform.Find("World").Find("Local");

            // constrain cull object to avatar
            Transform cull = marker.transform.Find("Cull");

            cull.GetComponent <ParentConstraint>().SetSource(0, new ConstraintSource {
                sourceTransform = descriptor.transform, weight = 1f
            });

            if (useIndexFinger)
            {
                DestroyImmediate(markerTarget.GetChild(0).gameObject);                 // destroy Flip
                Transform indexDistal = leftHanded ? avatar.GetBoneTransform(HumanBodyBones.LeftIndexDistal) : avatar.GetBoneTransform(HumanBodyBones.RightIndexDistal);

                // prefer the end bone of the index finger if it exists
                if (indexDistal.Find(indexDistal.gameObject.name + "_end") != null)
                {
                    markerTarget.SetParent(indexDistal.Find(indexDistal.gameObject.name + "_end"), true);
                }
                else
                {
                    markerTarget.SetParent(indexDistal, false);
                }
            }
            else                                         // using model: scale Model to target freely, and until script is destroyed, scale System to target uniformly with X-axis
            {
                markerModel.SetParent(marker.transform); // move it out of Targets hierarchy
                if (leftHanded)
                {
                    markerTarget.SetParent(avatar.GetBoneTransform(HumanBodyBones.LeftHand), true);
                }
                else
                {
                    markerTarget.SetParent(avatar.GetBoneTransform(HumanBodyBones.RightHand), true);
                }
                ((Marker)target).markerModel = markerModel;                 // to turn its mesh renderer off when script is finished
            }
            markerTarget.localPosition = Vector3.zero;
            markerTarget.localRotation = Quaternion.Euler(0f, 0f, 0f);

            HumanBodyBones[] bones = { HumanBodyBones.Hips,     HumanBodyBones.Chest, HumanBodyBones.Head, HumanBodyBones.LeftHand, HumanBodyBones.RightHand,
                                       HumanBodyBones.LeftFoot, HumanBodyBones.RightFoot };
            ParentConstraint localConstraint = local.GetComponent <ParentConstraint>();

            localConstraint.SetSource(0, new ConstraintSource {
                sourceTransform = avatar.transform, weight = 1f
            });
            if (localSpace)
            {
                for (int i = 0; i < 5; i++)
                {
                    localConstraint.SetSource(i + 1, new ConstraintSource {
                        sourceTransform = avatar.GetBoneTransform(bones[i]), weight = 0f
                    });
                }
                if (localSpaceFullBody == 1)
                {
                    for (int i = 5; i < 7; i++)
                    {
                        localConstraint.SetSource(i + 1, new ConstraintSource {
                            sourceTransform = avatar.GetBoneTransform(bones[i]), weight = 0f
                        });
                    }
                }
            }

            DestroyImmediate(targets.gameObject);             // remove the "Targets" container object when finished

            // set anything not adjustable to a medium-ish amount
            if (!eraserSize)
            {
                eraser.transform.localScale = new Vector3(0.05f, 0.05f, 0.05f);
            }
            if (!brushSize)
            {
                ParticleSystem.MinMaxCurve size = new ParticleSystem.MinMaxCurve(0.024f);
                Transform draw    = system.transform.Find("Draw");
                Transform preview = draw.GetChild(0);
                ParticleSystem.MainModule main = draw.GetComponent <ParticleSystem>().main;
                main.startSize = size;
                main           = preview.GetComponent <ParticleSystem>().main;
                main.startSize = size;
            }

            // scale MarkerTarget, which controls prefab size, according to a (normalized) worldspace distance between avatar hips and head
            Transform hips = avatar.GetBoneTransform(HumanBodyBones.Hips);
            Transform head = avatar.GetBoneTransform(HumanBodyBones.Head);
            Vector3   dist = (head.position - hips.position);

            float normalizedDist = (Math.Max(Math.Max(dist.x, dist.y), dist.z) / KSIVL_UNIT);
            float newScale       = markerTarget.localScale.x * normalizedDist;

            markerTarget.localScale = new Vector3(newScale, newScale, newScale);

            ((Marker)target).system       = system;
            ((Marker)target).markerTarget = markerTarget;
            ((Marker)target).finished     = true;
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
            Debug.Log("Successfully generated Marker!");
        }
 public VrcParameterDefinition AddParameter(VRCExpressionParameters.Parameter parameter)
 {
     return(Children.AddChild(ParameterFactory.Create(this, parameter)));
 }
    void DrawParameterDropDown(SerializedProperty parameter, string name, bool allowBool = true)
    {
        var parameterName = parameter.FindPropertyRelative("name");

        VRCExpressionParameters.Parameter param = null;
        string value = parameterName.stringValue;

        bool parameterFound = false;

        EditorGUILayout.BeginHorizontal();
        {
            if (activeDescriptor != null)
            {
                //Dropdown
                int currentIndex;
                if (string.IsNullOrEmpty(value))
                {
                    currentIndex   = -1;
                    parameterFound = true;
                }
                else
                {
                    currentIndex = -2;
                    for (int i = 0; i < GetExpressionParametersCount(); i++)
                    {
                        var item = activeDescriptor.GetExpressionParameter(i);
                        if (item.name == value)
                        {
                            param          = item;
                            parameterFound = true;
                            currentIndex   = i;
                            break;
                        }
                    }
                }

                //Dropdown
                EditorGUI.BeginChangeCheck();
                currentIndex = EditorGUILayout.Popup(name, currentIndex + 1, parameterNames);
                if (EditorGUI.EndChangeCheck())
                {
                    if (currentIndex == 0)
                    {
                        parameterName.stringValue = "";
                    }
                    else
                    {
                        parameterName.stringValue = GetExpressionParameter(currentIndex - 1).name;
                    }
                }
            }
            else
            {
                EditorGUI.BeginDisabledGroup(true);
                EditorGUILayout.Popup(0, new string[0]);
                EditorGUI.EndDisabledGroup();
            }

            //Text field
            parameterName.stringValue = EditorGUILayout.TextField(parameterName.stringValue, GUILayout.MaxWidth(200));
        }
        EditorGUILayout.EndHorizontal();

        if (!parameterFound)
        {
            EditorGUILayout.HelpBox("Parameter not found on the active avatar descriptor.", MessageType.Warning);
        }

        if (!allowBool && param != null && param.valueType == ExpressionParameters.ValueType.Bool)
        {
            EditorGUILayout.HelpBox("Bool parameters not valid for this choice.", MessageType.Error);
        }
    }
        public override void ValidateFeatures(VRC_AvatarDescriptor avatar, Animator anim, AvatarPerformanceStats perfStats)
        {
            //Create avatar debug hashset
            VRCAvatarDescriptor avatarSDK3 = avatar as VRCAvatarDescriptor;

            if (avatarSDK3 != null)
            {
                avatarSDK3.animationHashSet.Clear();

                foreach (VRCAvatarDescriptor.CustomAnimLayer animLayer in avatarSDK3.baseAnimationLayers)
                {
                    AnimatorController controller = animLayer.animatorController as AnimatorController;
                    if (controller != null)
                    {
                        foreach (AnimatorControllerLayer layer in controller.layers)
                        {
                            ProcessStateMachine(layer.stateMachine, "");
                            void ProcessStateMachine(AnimatorStateMachine stateMachine, string prefix)
                            {
                                //Update prefix
                                prefix = prefix + stateMachine.name + ".";

                                //States
                                foreach (var state in stateMachine.states)
                                {
                                    VRCAvatarDescriptor.DebugHash hash = new VRCAvatarDescriptor.DebugHash();
                                    string fullName = prefix + state.state.name;
                                    hash.hash = Animator.StringToHash(fullName);
                                    hash.name = fullName.Remove(0, layer.stateMachine.name.Length + 1);
                                    avatarSDK3.animationHashSet.Add(hash);
                                }

                                //Sub State Machines
                                foreach (var subMachine in stateMachine.stateMachines)
                                {
                                    ProcessStateMachine(subMachine.stateMachine, prefix);
                                }
                            }
                        }
                    }
                }
            }

            //Validate Playable Layers
            if (avatarSDK3 != null && avatarSDK3.customizeAnimationLayers)
            {
                VRCAvatarDescriptor.CustomAnimLayer gestureLayer = avatarSDK3.baseAnimationLayers[2];
                if (anim != null &&
                    anim.isHuman &&
                    gestureLayer.animatorController != null &&
                    gestureLayer.type == VRCAvatarDescriptor.AnimLayerType.Gesture &&
                    !gestureLayer.isDefault)
                {
                    AnimatorController controller = gestureLayer.animatorController as AnimatorController;
                    if (controller != null && controller.layers[0].avatarMask == null)
                    {
                        _builder.OnGUIError(avatar, "Gesture Layer needs valid mask on first animator layer",
                                            delegate { OpenAnimatorControllerWindow(controller); }, null);
                    }
                }
            }

            //Expression menu images
            if (avatarSDK3 != null)
            {
                bool ValidateTexture(Texture2D texture)
                {
                    string          path     = AssetDatabase.GetAssetPath(texture);
                    TextureImporter importer = AssetImporter.GetAtPath(path) as TextureImporter;

                    if (importer == null)
                    {
                        return(true);
                    }
                    TextureImporterPlatformSettings settings = importer.GetDefaultPlatformTextureSettings();

                    //Max texture size
                    if ((texture.width > MAX_ACTION_TEXTURE_SIZE || texture.height > MAX_ACTION_TEXTURE_SIZE) &&
                        settings.maxTextureSize > MAX_ACTION_TEXTURE_SIZE)
                    {
                        return(false);
                    }

                    //Compression
                    if (settings.textureCompression == TextureImporterCompression.Uncompressed)
                    {
                        return(false);
                    }

                    //Success
                    return(true);
                }

                void FixTexture(Texture2D texture)
                {
                    string          path     = AssetDatabase.GetAssetPath(texture);
                    TextureImporter importer = AssetImporter.GetAtPath(path) as TextureImporter;

                    if (importer == null)
                    {
                        return;
                    }
                    TextureImporterPlatformSettings settings = importer.GetDefaultPlatformTextureSettings();

                    //Max texture size
                    if (texture.width > MAX_ACTION_TEXTURE_SIZE || texture.height > MAX_ACTION_TEXTURE_SIZE)
                    {
                        settings.maxTextureSize = Math.Min(settings.maxTextureSize, MAX_ACTION_TEXTURE_SIZE);
                    }

                    //Compression
                    if (settings.textureCompression == TextureImporterCompression.Uncompressed)
                    {
                        settings.textureCompression = TextureImporterCompression.Compressed;
                    }

                    //Set & Reimport
                    importer.SetPlatformTextureSettings(settings);
                    AssetDatabase.ImportAsset(path);
                }

                //Find all textures
                List <Texture2D>          textures  = new List <Texture2D>();
                List <VRCExpressionsMenu> menuStack = new List <VRCExpressionsMenu>();
                FindTextures(avatarSDK3.expressionsMenu);

                void FindTextures(VRCExpressionsMenu menu)
                {
                    if (menu == null || menuStack.Contains(menu)) //Prevent recursive menu searching
                    {
                        return;
                    }
                    menuStack.Add(menu);

                    //Check controls
                    foreach (VRCExpressionsMenu.Control control in menu.controls)
                    {
                        AddTexture(control.icon);
                        if (control.labels != null)
                        {
                            foreach (VRCExpressionsMenu.Control.Label label in control.labels)
                            {
                                AddTexture(label.icon);
                            }
                        }

                        if (control.subMenu != null)
                        {
                            FindTextures(control.subMenu);
                        }
                    }

                    void AddTexture(Texture2D texture)
                    {
                        if (texture != null)
                        {
                            textures.Add(texture);
                        }
                    }
                }

                //Validate
                bool isValid = true;
                foreach (Texture2D texture in textures)
                {
                    if (!ValidateTexture(texture))
                    {
                        isValid = false;
                    }
                }

                if (!isValid)
                {
                    _builder.OnGUIError(avatar, "Images used for Actions & Moods are too large.",
                                        delegate { Selection.activeObject = avatar.gameObject; }, FixTextures);
                }

                //Fix
                void FixTextures()
                {
                    foreach (Texture2D texture in textures)
                    {
                        FixTexture(texture);
                    }
                }
            }

            //Expression menu parameters
            if (avatarSDK3 != null)
            {
                //Check for expression menu/parameters object
                if (avatarSDK3.expressionsMenu != null || avatarSDK3.expressionParameters != null)
                {
                    //Menu
                    if (avatarSDK3.expressionsMenu == null)
                    {
                        _builder.OnGUIError(avatar, "VRCExpressionsMenu object reference is missing.",
                                            delegate { Selection.activeObject = avatarSDK3; }, null);
                    }

                    //Parameters
                    if (avatarSDK3.expressionParameters == null)
                    {
                        _builder.OnGUIError(avatar, "VRCExpressionParameters object reference is missing.",
                                            delegate { Selection.activeObject = avatarSDK3; }, null);
                    }
                }

                //Check if parameters is valid
                if (avatarSDK3.expressionParameters != null && avatarSDK3.expressionParameters.CalcTotalCost() > VRCExpressionParameters.MAX_PARAMETER_COST)
                {
                    _builder.OnGUIError(avatar, "VRCExpressionParameters has too many parameters defined.",
                                        delegate { Selection.activeObject = avatarSDK3.expressionParameters; }, null);
                }

                //Find all existing parameters
                if (avatarSDK3.expressionsMenu != null && avatarSDK3.expressionParameters != null)
                {
                    List <VRCExpressionsMenu> menuStack  = new List <VRCExpressionsMenu>();
                    List <string>             parameters = new List <string>();
                    List <VRCExpressionsMenu> selects    = new List <VRCExpressionsMenu>();
                    FindParameters(avatarSDK3.expressionsMenu);

                    void FindParameters(VRCExpressionsMenu menu)
                    {
                        if (menu == null || menuStack.Contains(menu)) //Prevent recursive menu searching
                        {
                            return;
                        }
                        menuStack.Add(menu);

                        //Check controls
                        foreach (VRCExpressionsMenu.Control control in menu.controls)
                        {
                            AddParameter(control.parameter);
                            if (control.subParameters != null)
                            {
                                foreach (VRCExpressionsMenu.Control.Parameter subParameter in control.subParameters)
                                {
                                    AddParameter(subParameter);
                                }
                            }

                            if (control.subMenu != null)
                            {
                                FindParameters(control.subMenu);
                            }
                        }

                        void AddParameter(VRCExpressionsMenu.Control.Parameter parameter)
                        {
                            if (parameter != null)
                            {
                                parameters.Add(parameter.name);
                                selects.Add(menu);
                            }
                        }
                    }

                    //Validate parameters
                    for (int i = 0; i < parameters.Count; i++)
                    {
                        string             parameter = parameters[i];
                        VRCExpressionsMenu select    = selects[i];

                        //Find
                        bool exists = string.IsNullOrEmpty(parameter) || avatarSDK3.expressionParameters.FindParameter(parameter) != null;
                        if (!exists)
                        {
                            _builder.OnGUIError(avatar,
                                                "VRCExpressionsMenu uses a parameter that is not defined.\nParameter: " + parameter,
                                                delegate { Selection.activeObject = select; }, null);
                        }
                    }

                    //Validate param choices
                    foreach (var menu in menuStack)
                    {
                        foreach (var control in menu.controls)
                        {
                            bool isValid = true;
                            if (control.type == VRCExpressionsMenu.Control.ControlType.FourAxisPuppet)
                            {
                                isValid &= ValidateNonBoolParam(control.subParameters[0].name);
                                isValid &= ValidateNonBoolParam(control.subParameters[1].name);
                                isValid &= ValidateNonBoolParam(control.subParameters[2].name);
                                isValid &= ValidateNonBoolParam(control.subParameters[3].name);
                            }
                            else if (control.type == VRCExpressionsMenu.Control.ControlType.RadialPuppet)
                            {
                                isValid &= ValidateNonBoolParam(control.subParameters[0].name);
                            }
                            else if (control.type == VRCExpressionsMenu.Control.ControlType.TwoAxisPuppet)
                            {
                                isValid &= ValidateNonBoolParam(control.subParameters[0].name);
                                isValid &= ValidateNonBoolParam(control.subParameters[1].name);
                            }
                            if (!isValid)
                            {
                                _builder.OnGUIError(avatar,
                                                    "VRCExpressionsMenu uses an invalid parameter for a control.\nControl: " + control.name,
                                                    delegate { Selection.activeObject = menu; }, null);
                            }
                        }

                        bool ValidateNonBoolParam(string name)
                        {
                            VRCExpressionParameters.Parameter param = string.IsNullOrEmpty(name) ? null : avatarSDK3.expressionParameters.FindParameter(name);
                            if (param != null && param.valueType == VRCExpressionParameters.ValueType.Bool)
                            {
                                return(false);
                            }
                            return(true);
                        }
                    }
                }
            }

            IEnumerable <Component> componentsToRemove      = AvatarValidation.FindIllegalComponents(avatar.gameObject);
            HashSet <string>        componentsToRemoveNames = new HashSet <string>();
            IEnumerable <Component> toRemove = componentsToRemove as Component[] ?? componentsToRemove.ToArray();

            foreach (Component c in toRemove)
            {
                if (componentsToRemoveNames.Contains(c.GetType().Name) == false)
                {
                    componentsToRemoveNames.Add(c.GetType().Name);
                }
            }

            if (componentsToRemoveNames.Count > 0)
            {
                _builder.OnGUIError(avatar,
                                    "The following component types are found on the Avatar and will be removed by the client: " +
                                    string.Join(", ", componentsToRemoveNames.ToArray()),
                                    delegate { ShowRestrictedComponents(toRemove); },
                                    delegate { FixRestrictedComponents(toRemove); });
            }

            List <AudioSource> audioSources =
                avatar.gameObject.GetComponentsInChildren <AudioSource>(true).ToList();

            if (audioSources.Count > 0)
            {
                _builder.OnGUIWarning(avatar,
                                      "Audio sources found on Avatar, they will be adjusted to safe limits, if necessary.",
                                      GetAvatarSubSelectAction(avatar, typeof(AudioSource)), null);
            }

            List <VRCStation> stations =
                avatar.gameObject.GetComponentsInChildren <VRCStation>(true).ToList();

            if (stations.Count > 0)
            {
                _builder.OnGUIWarning(avatar, "Stations found on Avatar, they will be adjusted to safe limits, if necessary.",
                                      GetAvatarSubSelectAction(avatar, typeof(VRCStation)), null);
            }

            if (VRCSdkControlPanel.HasSubstances(avatar.gameObject))
            {
                _builder.OnGUIWarning(avatar,
                                      "This avatar has one or more Substance materials, which is not supported and may break in-game. Please bake your Substances to regular materials.",
                                      () => { Selection.objects = VRCSdkControlPanel.GetSubstanceObjects(avatar.gameObject); },
                                      null);
            }

            CheckAvatarMeshesForLegacyBlendShapesSetting(avatar);

#if UNITY_ANDROID
            IEnumerable <Shader> illegalShaders = AvatarValidation.FindIllegalShaders(avatar.gameObject);
            foreach (Shader s in illegalShaders)
            {
                _builder.OnGUIError(avatar, "Avatar uses unsupported shader '" + s.name + "'. You can only use the shaders provided in 'VRChat/Mobile' for Quest avatars.", delegate() { Selection.activeObject
                                                                                                                                                                                             = avatar.gameObject; }, null);
            }
#endif

            foreach (AvatarPerformanceCategory perfCategory in Enum.GetValues(typeof(AvatarPerformanceCategory)))
            {
                if (perfCategory == AvatarPerformanceCategory.Overall ||
                    perfCategory == AvatarPerformanceCategory.PolyCount ||
                    perfCategory == AvatarPerformanceCategory.AABB ||
                    perfCategory == AvatarPerformanceCategory.AvatarPerformanceCategoryCount)
                {
                    continue;
                }

                Action show = null;

                switch (perfCategory)
                {
                case AvatarPerformanceCategory.AnimatorCount:
                    show = GetAvatarSubSelectAction(avatar, typeof(Animator));
                    break;

                case AvatarPerformanceCategory.AudioSourceCount:
                    show = GetAvatarSubSelectAction(avatar, typeof(AudioSource));
                    break;

                case AvatarPerformanceCategory.BoneCount:
                    show = GetAvatarSubSelectAction(avatar, typeof(SkinnedMeshRenderer));
                    break;

                case AvatarPerformanceCategory.ClothCount:
                    show = GetAvatarSubSelectAction(avatar, typeof(Cloth));
                    break;

                case AvatarPerformanceCategory.ClothMaxVertices:
                    show = GetAvatarSubSelectAction(avatar, typeof(Cloth));
                    break;

                case AvatarPerformanceCategory.LightCount:
                    show = GetAvatarSubSelectAction(avatar, typeof(Light));
                    break;

                case AvatarPerformanceCategory.LineRendererCount:
                    show = GetAvatarSubSelectAction(avatar, typeof(LineRenderer));
                    break;

                case AvatarPerformanceCategory.MaterialCount:
                    show = GetAvatarSubSelectAction(avatar,
                                                    new[] { typeof(MeshRenderer), typeof(SkinnedMeshRenderer) });
                    break;

                case AvatarPerformanceCategory.MeshCount:
                    show = GetAvatarSubSelectAction(avatar,
                                                    new[] { typeof(MeshRenderer), typeof(SkinnedMeshRenderer) });
                    break;

                case AvatarPerformanceCategory.ParticleCollisionEnabled:
                    show = GetAvatarSubSelectAction(avatar, typeof(ParticleSystem));
                    break;

                case AvatarPerformanceCategory.ParticleMaxMeshPolyCount:
                    show = GetAvatarSubSelectAction(avatar, typeof(ParticleSystem));
                    break;

                case AvatarPerformanceCategory.ParticleSystemCount:
                    show = GetAvatarSubSelectAction(avatar, typeof(ParticleSystem));
                    break;

                case AvatarPerformanceCategory.ParticleTotalCount:
                    show = GetAvatarSubSelectAction(avatar, typeof(ParticleSystem));
                    break;

                case AvatarPerformanceCategory.ParticleTrailsEnabled:
                    show = GetAvatarSubSelectAction(avatar, typeof(ParticleSystem));
                    break;

                case AvatarPerformanceCategory.PhysicsColliderCount:
                    show = GetAvatarSubSelectAction(avatar, typeof(Collider));
                    break;

                case AvatarPerformanceCategory.PhysicsRigidbodyCount:
                    show = GetAvatarSubSelectAction(avatar, typeof(Rigidbody));
                    break;

                case AvatarPerformanceCategory.PolyCount:
                    show = GetAvatarSubSelectAction(avatar,
                                                    new[] { typeof(MeshRenderer), typeof(SkinnedMeshRenderer) });
                    break;

                case AvatarPerformanceCategory.SkinnedMeshCount:
                    show = GetAvatarSubSelectAction(avatar, typeof(SkinnedMeshRenderer));
                    break;

                case AvatarPerformanceCategory.TrailRendererCount:
                    show = GetAvatarSubSelectAction(avatar, typeof(TrailRenderer));
                    break;
                }

                // we can only show these buttons if DynamicBone is installed

                Type dynamicBoneType         = typeof(AvatarValidation).Assembly.GetType("DynamicBone");
                Type dynamicBoneColliderType = typeof(AvatarValidation).Assembly.GetType("DynamicBoneCollider");
                if ((dynamicBoneType != null) && (dynamicBoneColliderType != null))
                {
                    switch (perfCategory)
                    {
                    case AvatarPerformanceCategory.DynamicBoneColliderCount:
                        show = GetAvatarSubSelectAction(avatar, dynamicBoneColliderType);
                        break;

                    case AvatarPerformanceCategory.DynamicBoneCollisionCheckCount:
                        show = GetAvatarSubSelectAction(avatar, dynamicBoneColliderType);
                        break;

                    case AvatarPerformanceCategory.DynamicBoneComponentCount:
                        show = GetAvatarSubSelectAction(avatar, dynamicBoneType);
                        break;

                    case AvatarPerformanceCategory.DynamicBoneSimulatedBoneCount:
                        show = GetAvatarSubSelectAction(avatar, dynamicBoneType);
                        break;
                    }
                }

                OnGUIPerformanceInfo(avatar, perfStats, perfCategory, show, null);
            }

            _builder.OnGUILink(avatar, "Avatar Optimization Tips", VRCSdkControlPanel.AVATAR_OPTIMIZATION_TIPS_URL);
        }
示例#19
0
    private void ShowMenuFoldout(VRCExpressionsMenu menu, string title)
    {
        if (menu == null)
        {
            return;
        }

        bool b = expandedMenus.Contains(menu);

        // Remove before we go any further, prevents infinite recursion on cyclic menus.
        expandedMenus.Remove(menu);


        if (!EditorGUILayout.Foldout(b, title, true))
        {
            return;
        }

        EditorGUILayout.BeginVertical();
        GUILayout.BeginHorizontal();
        GUILayout.Space(EditorGUI.indentLevel * 17);
        Debug.Log(expressionParams.parameters.Length + ":" + menu.controls.Count);

        int size = 0;

        for (int i = 0; i < expressionParams.parameters.Length; i++)
        {
            size += VRCExpressionParameters.TypeCost(expressionParams.parameters[i].valueType);
        }

        if (menu.controls.Count < expressionParams.parameters.Length)
        {
            if (GUILayout.Button("Add Marker Here", GUILayout.Width(130)))
            {
                InstallMarker(ref menu);
            }
        }
        else
        {
            if (size < VRCExpressionParameters.MAX_PARAMETER_COST)
            {
                if (GUILayout.Button("enlarge parameters", GUILayout.Width(130)))
                {
                    if (size < VRCExpressionParameters.MAX_PARAMETER_COST)
                    {
                        VRCExpressionParameters.Parameter[] newParams = new VRCExpressionParameters.Parameter[expressionParams.parameters.Length + 1];
                        for (int i = 0; i < expressionParams.parameters.Length; i++)
                        {
                            newParams[i] = expressionParams.parameters[i];
                        }
                        newParams[expressionParams.parameters.Length] = new VRCExpressionParameters.Parameter();
                        expressionParams.parameters = newParams;
                        EditorUtility.SetDirty(expressionParams);
                    }
                }
            }
            else
            {
                GUILayout.Label("No room.", GUILayout.Width(130));
            }
        }
        GUILayout.EndHorizontal();

        EditorGUI.indentLevel++;
        foreach (var child in menu.controls)
        {
            if (child.type == ControlType.SubMenu)
            {
                ShowMenuFoldout(child.subMenu, child.name);
            }
        }
        EditorGUI.indentLevel--;
        EditorGUILayout.EndVertical();

        // Okay, it's safe to add the menu back.
        expandedMenus.Add(menu);
    }
示例#20
0
        private bool VRC_Actions(string songLibrary, List <AudioClip> libAssets, Avatar8TrackEditor _8Track)
        {
            //--- --- VRC Expression Parameters --- ---
            if (null != expressionParameters)
            {
                VRCExpressionParameters.Parameter volumeParam = new VRCExpressionParameters.Parameter()
                {
                    name = _8Track.VolumeEPName, valueType = VRCExpressionParameters.ValueType.Float
                };
                VRCExpressionParameters.Parameter trackParam = new VRCExpressionParameters.Parameter()
                {
                    name = _8Track.TrackEPName, valueType = VRCExpressionParameters.ValueType.Int
                };

                VRCExpressionParameters.Parameter[] parameters = expressionParameters.parameters;
                bool hasTrack  = false;
                bool hasVolume = false;
                foreach (VRCExpressionParameters.Parameter parameter in parameters)
                {
                    if (parameter.name == _8TrackEditor.VolumeEPName)
                    {
                        hasVolume = true;
                    }
                    else if (parameter.name == _8TrackEditor.TrackEPName)
                    {
                        hasTrack = true;
                    }
                }

                if (!hasVolume)
                {
                    ArrayUtility.Add <VRCExpressionParameters.Parameter>(ref expressionParameters.parameters, volumeParam);
                }
                if (!hasTrack)
                {
                    ArrayUtility.Add <VRCExpressionParameters.Parameter>(ref expressionParameters.parameters, trackParam);
                }

                UnityEditor.EditorUtility.SetDirty(expressionParameters);
            }

            //--- --- VRC Expression Menu --- ---
            VRCExpressionsMenu mainMenu = new VRCExpressionsMenu()
            {
                name = _8Track._8TrackObject.name + " Menu"
            };

            mainMenu.controls.Add(new VRCExpressionsMenu.Control()
            {
                icon = _8Track.StopIcon, name = "Stop", parameter = new VRCExpressionsMenu.Control.Parameter()
                {
                    name = _8Track.TrackEPName
                }, type = VRCExpressionsMenu.Control.ControlType.Toggle, value = 0
            });
            mainMenu.controls.Add(new VRCExpressionsMenu.Control()
            {
                icon = _8Track.VolumeIcon, name = "Volume", subParameters = new VRCExpressionsMenu.Control.Parameter[] { new VRCExpressionsMenu.Control.Parameter()
                                                                                                                         {
                                                                                                                             name = _8Track.VolumeEPName
                                                                                                                         } }, type = VRCExpressionsMenu.Control.ControlType.RadialPuppet
            });

            VRCExpressionsMenu disk = new VRCExpressionsMenu()
            {
                name = "Disk " + 1
            };

            mainMenu.controls.Add(new VRCExpressionsMenu.Control()
            {
                icon = _8Track.DiskIcon, name = disk.name, type = VRCExpressionsMenu.Control.ControlType.SubMenu, subMenu = disk
            });

            int menuCount = 3;
            VRCExpressionsMenu        menu  = mainMenu;
            List <VRCExpressionsMenu> menus = new List <VRCExpressionsMenu>();

            int diskCount = 0;
            List <VRCExpressionsMenu> disks = new List <VRCExpressionsMenu>
            {
                disk
            };

            int trackNumber = 0;

            do
            {
                if (libAssets.Count <= trackNumber)
                {
                    break;
                }

                string trackName = libAssets[trackNumber].name;
                trackNumber++;

                if (diskCount == 8)
                {
                    VRCExpressionsMenu newDisk = new VRCExpressionsMenu()
                    {
                        name = "Disk " + (disks.Count + 1)
                    };

                    if (7 == menuCount && 0 < libAssets.Count - (trackNumber))
                    {
                        VRCExpressionsMenu newMenu = new VRCExpressionsMenu()
                        {
                            name = "More..."
                        };
                        menu.controls.Add(new VRCExpressionsMenu.Control()
                        {
                            icon = _8Track.FolderIcon, name = newMenu.name, type = VRCExpressionsMenu.Control.ControlType.SubMenu, subMenu = newMenu
                        });
                        menus.Add(newMenu);
                        menu      = newMenu;
                        menuCount = 0;
                    }
                    menu.controls.Add(new VRCExpressionsMenu.Control()
                    {
                        icon = _8Track.DiskIcon, name = newDisk.name, type = VRCExpressionsMenu.Control.ControlType.SubMenu, subMenu = newDisk
                    });
                    menuCount++;
                    disks.Add(newDisk);
                    disk      = newDisk;
                    diskCount = 0;
                }

                disk.controls.Add(new VRCExpressionsMenu.Control()
                {
                    icon = _8Track.TrackIcon, name = trackName, parameter = new VRCExpressionsMenu.Control.Parameter()
                    {
                        name = _8Track.TrackEPName
                    }, type = VRCExpressionsMenu.Control.ControlType.Toggle, value = trackNumber
                });
                diskCount++;
            } while(true);

            foreach (VRCExpressionsMenu d in disks)
            {
                CreateAsset(_8Track.AudioClip, d, d.name + ".asset");
                EditorUtility.SetDirty(d);
            }

            CreateAsset(_8Track.AudioClip, mainMenu, mainMenu.name + ".asset");
            EditorUtility.SetDirty(mainMenu);
            for (int i = 0; i < menus.Count; i++)
            {
                CreateAsset(_8TrackEditor.AudioClip, menus[i], _8Track._8TrackObject.name + " Menu " + i + ".asset");
            }

            if (null != expressionsMenu)
            {
                VRCExpressionsMenu.Control toggle = GetMenuControl();
                expressionsMenu.controls.Remove(toggle);
                expressionsMenu.controls.Add(new VRCExpressionsMenu.Control()
                {
                    icon = _8Track.FolderIcon, name = _8TrackEditor._8TrackObject.name, type = VRCExpressionsMenu.Control.ControlType.SubMenu, subMenu = mainMenu
                });
                EditorUtility.SetDirty(expressionsMenu);
            }
            EditorUtility.SetDirty(expressionParameters);
            AssetDatabase.SaveAssets();
            return(true);
        }