예제 #1
0
        static bool ValidateThereIsARoot(SerializedProperty rootNameProperty, SerializedProperty boneList, bool doGUI)
        {
            string rootName = rootNameProperty.FindPropertyRelative("name").stringValue;

            bool rootExists = false;

            for (int i = 0; i < boneList.arraySize; i++)
            {
                string currentBone = boneList.GetArrayElementAtIndex(i).FindPropertyRelative("name").stringValue;
                if (currentBone == rootName)
                {
                    rootExists = true;
                    break;
                }
            }

            if (!rootExists)
            {
                if (boneList.arraySize == 1)
                {
                    rootNameProperty.stringValue = boneList.GetArrayElementAtIndex(0).FindPropertyRelative("name").stringValue;
                }
                else
                {
                    if (doGUI)
                    {
                        NaughtyEditorGUI.HelpBox_Layout("A bone must be selected as root bone.", MessageType.Error);
                    }
                    return(false);
                }
            }

            return(true);
        }
예제 #2
0
        void ValidateNoDuplicateOverrides(ReorderableList list)
        {
            bool isValid = true;

            bonesWithOverride.Clear();

            for (int i = 0; i < list.serializedProperty.arraySize; i++)
            {
                string bone = list.serializedProperty.GetArrayElementAtIndex(i).FindPropertyRelative("bone.name").stringValue;

                if (bonesWithOverride.Contains(bone))
                {
                    NaughtyEditorGUI.HelpBox_Layout($"Bone \"{bone}\" is duplicated.", MessageType.Warning, logToConsole: false);
                    if (GUILayout.Button("Fix duplicate bone"))
                    {
                        list.serializedProperty.DeleteArrayElementAtIndex(i);
                        i--;
                    }

                    isValid = false;
                }
                else
                {
                    bonesWithOverride.Add(bone);
                }
            }

            if (!isValid)
            {
                SetIsNotValid();
            }
        }
예제 #3
0
        static bool ValidateNoEmptyNames(SerializedProperty boneList, bool doGUI)
        {
            bool hasEmptyNames = false;

            for (int i = 0; i < boneList.arraySize; i++)
            {
                string currentBone = boneList.GetArrayElementAtIndex(i).FindPropertyRelative("name").stringValue;
                if (string.IsNullOrEmpty(currentBone))
                {
                    hasEmptyNames = true;
                    break;
                }
            }

            if (hasEmptyNames)
            {
                if (doGUI)
                {
                    NaughtyEditorGUI.HelpBox_Layout("Empty bone names are not allowed.", MessageType.Error);
                }
                return(false);
            }
            else
            {
                return(true);
            }
        }
예제 #4
0
        private void ShowQuickBuildTab()
        {
            EditorGUILayout.Space();

            EditorGUILayout.HelpBox("Automatically sets build settings to get MVB " +
                                    "(minimum viable build) by including only necessary scenes.\n\n" +
                                    "Operates independently of the main build window. Settings are persistent and won't be picked up by git " +
                                    "(except Quick Load which is handled externally, so be sure to not commit that change).", MessageType.Info);

            NaughtyEditorGUI.PropertyField_Layout(mainStationProperty, false);
            mainStationScene = mainStationProperty.stringValue;
            ValidateMainStationScene(mainStationScene);

            EditorGUI.BeginChangeCheck();
            var quickLoadLabel = new GUIContent(
                "Quick Load",
                "At runtime, skips the lobby scene and boots you straight into the map.");

            EditorGUILayout.Toggle(quickLoadLabel, QuickLoad.IsEnabled);
            if (EditorGUI.EndChangeCheck())
            {
                QuickLoad.Toggle();
            }

            EditorGUILayout.Space();

            target = (BuildTarget)EditorGUILayout.EnumPopup("Target Platform", target);
            if (BuildPipeline.IsBuildTargetSupported(default, target) == false)
예제 #5
0
        static bool ValidateNoDuplicateNames(SerializedProperty boneList, bool doGUI)
        {
            HashSet <string> duplicateSearchingSet = new HashSet <string>();

            bool hasDuplicates = false;

            for (int i = 0; i < boneList.arraySize; i++)
            {
                if (!duplicateSearchingSet.Add(boneList.GetArrayElementAtIndex(i).FindPropertyRelative("name").stringValue))
                {
                    hasDuplicates = true;
                    break;
                }
            }

            if (hasDuplicates)
            {
                if (doGUI)
                {
                    NaughtyEditorGUI.HelpBox_Layout("There are duplicate bone names. This is not allowed.", MessageType.Error);
                }
                return(false);
            }
            else
            {
                return(true);
            }
        }
        public static bool ValidateProfileField_Layout(SerializedProperty property, RagdollDefinition definition, bool isRequired)
        {
            string type = ReflectionUtility.GetField(property.serializedObject.targetObject, property.name).FieldType.Name;

            if (!property.objectReferenceValue)
            {
                if (isRequired)
                {
                    NaughtyEditorGUI.HelpBox_Layout($"A {type} is required.", MessageType.Error);
                    return(false);
                }
                else
                {
                    return(true);
                }
            }
            else if (!(property.objectReferenceValue as RagdollProfile).IsValid)
            {
                NaughtyEditorGUI.HelpBox_Layout($"The assigned {type} is not valid.", MessageType.Error);
                return(false);
            }
            else if (definition != null && (property.objectReferenceValue as RagdollProfile).IsCompatibleWith(definition) != definition)
            {
                NaughtyEditorGUI.HelpBox_Layout($"The bound RagdollDefinition and the {type}'s RagdollDefinition are incompatible.", MessageType.Error);
                return(false);
            }
            else
            {
                return(true);
            }
        }
    protected void DrawBaseProperties(params string[] excludedNames)
    {
        EditorGUILayout.Space();

        using (new EditorGUI.IndentLevelScope(1))
        {
            foreach (var prop in baseProperties)
            {
                if (excludedNames.Any(o => o == prop.name))
                {
                    continue;
                }
                if (isCallableArray(prop))
                {
                    reorderableLists[GetPropertyKeyName(prop)].DoLayoutList();
                }
                else
                {
                    NaughtyEditorGUI.PropertyField_Layout(prop, true);
                }
            }
        }

        DrawButtons();
    }
        public override void OnInspectorGUI()
        {
            serializedObject.Update();

            RagdollProfileEditorUtility.DrawDefinitionField_Layout(definition, true);

            hasValidDefinition = RagdollProfileEditorUtility.IsValid(definition);
            if (hasValidDefinition)
            {
                RagdollProfileEditorUtility.RefreshBoneDictionaryKeys(bindingsDictionary, definition);

                NaughtyEditorGUI.BeginBoxGroup_Layout("Bindings");

                EditorGUI.BeginDisabledGroup(Application.isPlaying);
                DrawBindingFields();
                DrawAutoCompleteButton();
                EditorGUI.EndDisabledGroup();

                NaughtyEditorGUI.EndBoxGroup_Layout();

                ValidateNoDuplicateJoints();
                ValidateNoUnassignedBones();
            }

            serializedObject.ApplyModifiedProperties();
        }
예제 #9
0
        protected override void OnGUI_Internal(Rect rect, SerializedProperty property, GUIContent label)
        {
            EditorGUI.BeginProperty(rect, label, property);

            System.Type propertyType = PropertyUtility.GetPropertyType(property);
            if (typeof(ScriptableObject).IsAssignableFrom(propertyType))
            {
                ScriptableObject scriptableObject = property.objectReferenceValue as ScriptableObject;
                if (scriptableObject == null)
                {
                    EditorGUI.PropertyField(rect, property, label, false);
                }
                else
                {
                    // Draw a foldout
                    Rect foldoutRect = new Rect()
                    {
                        x      = rect.x,
                        y      = rect.y,
                        width  = EditorGUIUtility.labelWidth,
                        height = EditorGUIUtility.singleLineHeight
                    };

                    property.isExpanded = EditorGUI.Foldout(foldoutRect, property.isExpanded, label, toggleOnLabelClick: true);

                    // Draw the scriptable object field
                    float indentLength = NaughtyEditorGUI.GetIndentLength(rect);
                    float labelWidth   = EditorGUIUtility.labelWidth - indentLength + NaughtyEditorGUI.HorizontalSpacing;
                    Rect  propertyRect = new Rect()
                    {
                        x      = rect.x + labelWidth,
                        y      = rect.y,
                        width  = rect.width - labelWidth,
                        height = EditorGUIUtility.singleLineHeight
                    };

                    EditorGUI.BeginChangeCheck();
                    property.objectReferenceValue = EditorGUI.ObjectField(propertyRect, GUIContent.none, property.objectReferenceValue, propertyType, false);
                    if (EditorGUI.EndChangeCheck())
                    {
                        property.serializedObject.ApplyModifiedProperties();
                    }

                    // Draw the child properties
                    if (property.isExpanded)
                    {
                        DrawChildProperties(rect, property);
                    }
                }
            }
            else
            {
                string message = $"{typeof(ExpandableAttribute).Name} can only be used on scriptable objects";
                DrawDefaultPropertyAndHelpBox(rect, property, message, MessageType.Warning);
            }

            EditorGUI.EndProperty();
        }
        public override void OnGUI(Rect position)
        {
            Rect rect = EditorGUI.IndentedRect(position);

            rect.y += EditorGUIUtility.singleLineHeight / 3.0f;
            HorizontalLineAttribute lineAttr = (HorizontalLineAttribute)attribute;

            NaughtyEditorGUI.HorizontalLine(rect, lineAttr.Height, lineAttr.Color.GetColor());
        }
        void DrawPowerProfile()
        {
            NaughtyEditorGUI.BeginBoxGroup_Layout("Power Settings");

            for (int i = 0; i < settingsKeys.arraySize; i++)
            {
                DrawPowerSetting(settingsKeys.GetArrayElementAtIndex(i), settingsValues.GetArrayElementAtIndex(i));
            }

            NaughtyEditorGUI.EndBoxGroup_Layout();
        }
        protected override void OnGUI_Internal(Rect rect, SerializedProperty property, GUIContent label)
        {
            if (property.isArray)
            {
                string key = GetPropertyKeyName(property);

                ReorderableList reorderableList = null;
                if (!_reorderableListsByPropertyName.ContainsKey(key))
                {
                    reorderableList = new ReorderableList(property.serializedObject, property, true, true, true, true)
                    {
                        drawHeaderCallback = (Rect r) =>
                        {
                            EditorGUI.LabelField(r, string.Format("{0}: {1}", label.text, property.arraySize), GetLabelStyle());
                            HandleDragAndDrop(r, reorderableList);
                        },

                        drawElementCallback = (Rect r, int index, bool isActive, bool isFocused) =>
                        {
                            SerializedProperty element = property.GetArrayElementAtIndex(index);
                            r.y     += 1.0f;
                            r.x     += 10.0f;
                            r.width -= 10.0f;

                            EditorGUI.PropertyField(new Rect(r.x, r.y, r.width, EditorGUIUtility.singleLineHeight), element, true);
                        },

                        elementHeightCallback = (int index) =>
                        {
                            return(EditorGUI.GetPropertyHeight(property.GetArrayElementAtIndex(index)) + 4.0f);
                        }
                    };

                    _reorderableListsByPropertyName[key] = reorderableList;
                }

                reorderableList = _reorderableListsByPropertyName[key];

                if (rect == default)
                {
                    reorderableList.DoLayoutList();
                }
                else
                {
                    reorderableList.DoList(rect);
                }
            }
            else
            {
                string message = typeof(ReorderableListAttribute).Name + " can be used only on arrays or lists";
                NaughtyEditorGUI.HelpBox_Layout(message, MessageType.Warning, context: property.serializedObject.targetObject);
                EditorGUILayout.PropertyField(property, true);
            }
        }
예제 #13
0
        void DrawFactors()
        {
            NaughtyEditorGUI.BeginBoxGroup_Layout("Distribution");

            for (int i = 0; i < factorsKeys.arraySize; i++)
            {
                DrawFactor(factorsKeys.GetArrayElementAtIndex(i), factorsValues.GetArrayElementAtIndex(i));
            }

            NaughtyEditorGUI.EndBoxGroup_Layout();
        }
 void ValidateNoUnassignedBones()
 {
     for (int i = 0; i < values.arraySize; i++)
     {
         if (values.GetArrayElementAtIndex(i).objectReferenceValue == null)
         {
             NaughtyEditorGUI.HelpBox_Layout("All bones must be bound to a ConfigurableJoint.", MessageType.Error);
             return;
         }
     }
 }
        public override void OnGUI(Rect rect)
        {
            InfoBoxAttribute infoBoxAttribute = (InfoBoxAttribute)attribute;

            float indentLength = NaughtyEditorGUI.GetIndentLength(rect);
            Rect  infoBoxRect  = new Rect(
                rect.x + indentLength,
                rect.y,
                rect.width - indentLength,
                GetHelpBoxHeight());

            DrawInfoBox(infoBoxRect, infoBoxAttribute.Text, infoBoxAttribute.Type);
        }
예제 #16
0
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        EditorGUI.PropertyField(position, property, label, true);

        Rect controlRect = EditorGUILayout.GetControlRect();

        if (controlRect != null)
        {
            controlRect.height = 2;
            controlRect.y     += controlRect.height * 4;
            NaughtyEditorGUI.HorizontalLine(controlRect, 2.0f, Gray);
        }
    }
예제 #17
0
        protected void DrawButtons()
        {
            if (_methods.Any())
            {
                EditorGUILayout.Space();
                EditorGUILayout.LabelField("Buttons", GetHeaderGUIStyle());
                NaughtyEditorGUI.HorizontalLine(
                    EditorGUILayout.GetControlRect(false), HorizontalLineAttribute.DefaultHeight, HorizontalLineAttribute.DefaultColor.GetColor());

                foreach (var method in _methods)
                {
                    NaughtyEditorGUI.Button(serializedObject.targetObject, method);
                }
            }
        }
예제 #18
0
        protected void DrawNativeProperties()
        {
            if (_nativeProperties.Any())
            {
                EditorGUILayout.Space();
                EditorGUILayout.LabelField("Native Properties", GetHeaderGUIStyle());
                NaughtyEditorGUI.HorizontalLine(
                    EditorGUILayout.GetControlRect(false), HorizontalLineAttribute.DefaultHeight, HorizontalLineAttribute.DefaultColor.GetColor());

                foreach (var property in _nativeProperties)
                {
                    NaughtyEditorGUI.NativeProperty_Layout(serializedObject.targetObject, property);
                }
            }
        }
        public static void DrawDefinitionField_Layout(SerializedProperty definition, bool isRequired)
        {
            EditorGUI.BeginDisabledGroup(Application.isPlaying);
            EditorGUILayout.PropertyField(definition);
            EditorGUI.EndDisabledGroup();

            if (isRequired && !HasDefinition(definition))
            {
                NaughtyEditorGUI.HelpBox_Layout("A RagdollDefinition must be assigned.", MessageType.Error);
            }
            else if (HasDefinition(definition) && !IsValid(definition))
            {
                NaughtyEditorGUI.HelpBox_Layout("The Ragdoll Definition is invalid.", MessageType.Error);
            }
        }
예제 #20
0
        protected void DrawNonSerializedFields()
        {
            if (_nonSerializedFields.Any())
            {
                EditorGUILayout.Space();
                EditorGUILayout.LabelField("Non-Serialized Fields", GetHeaderGUIStyle());
                NaughtyEditorGUI.HorizontalLine(
                    EditorGUILayout.GetControlRect(false), HorizontalLineAttribute.DefaultHeight, HorizontalLineAttribute.DefaultColor.GetColor());

                foreach (var field in _nonSerializedFields)
                {
                    NaughtyEditorGUI.NonSerializedField_Layout(serializedObject.targetObject, field);
                }
            }
        }
예제 #21
0
        void WarnAgainstUnstablePositionMatchingParameters()
        {
            bool hasUnstableSettings = false;

            if (!PositionMatchingParametersAreStable(serializedObject.FindProperty("globalPositionAlpha").floatValue, serializedObject.FindProperty("globalPositionDampingRatio").floatValue))
            {
                hasUnstableSettings = true;
            }

            for (int i = 0; i < positionMatchingOverridesList.serializedProperty.arraySize && !hasUnstableSettings; i++)
            {
                if (!PositionMatchingParametersAreStable(
                        positionMatchingOverridesList.serializedProperty.GetArrayElementAtIndex(i).FindPropertyRelative("alpha").floatValue,
                        positionMatchingOverridesList.serializedProperty.GetArrayElementAtIndex(i).FindPropertyRelative("dampingRatio").floatValue))
                {
                    hasUnstableSettings = true;
                }
            }

            if (hasUnstableSettings)
            {
                NaughtyEditorGUI.HelpBox_Layout($"Settings where (alpha + dampingRatio > {MAX_STABLE_ALPHA_PLUS_DAMPING}) are often unstable. Consider lowering the parameters."
                                                , MessageType.Warning, logToConsole: false);

                if (GUILayout.Button("Fix unstable parameters"))
                {
                    FixUnstableParameters(serializedObject.FindProperty("globalPositionAlpha"), serializedObject.FindProperty("globalPositionDampingRatio"));

                    for (int i = 0; i < positionMatchingOverridesList.serializedProperty.arraySize; i++)
                    {
                        FixUnstableParameters(
                            positionMatchingOverridesList.serializedProperty.GetArrayElementAtIndex(i).FindPropertyRelative("alpha"),
                            positionMatchingOverridesList.serializedProperty.GetArrayElementAtIndex(i).FindPropertyRelative("dampingRatio")
                            );
                    }
                }
            }


            void FixUnstableParameters(SerializedProperty alpha, SerializedProperty dampingRatio)
            {
                if (!PositionMatchingParametersAreStable(alpha.floatValue, dampingRatio.floatValue))
                {
                    alpha.floatValue = MAX_STABLE_ALPHA_PLUS_DAMPING - dampingRatio.floatValue;
                }
            }
        }
예제 #22
0
        static bool ValidateNotEmpty(SerializedProperty boneList, bool doGUI)
        {
            bool isEmpty = boneList.arraySize == 0;

            if (isEmpty)
            {
                if (doGUI)
                {
                    NaughtyEditorGUI.HelpBox_Layout("At least 1 bone is required.", MessageType.Error);
                }
                return(false);
            }
            else
            {
                return(true);
            }
        }
예제 #23
0
        protected override void OnGUI_Internal(Rect rect, SerializedProperty property, GUIContent label)
        {
            if (property.hasChildren)
            {
                InlineAttribute attribute = PropertyUtility.GetAttribute <InlineAttribute>(property);

                if (attribute.ShowHeaderAndBox)
                {
                    rect.position += new Vector2(0, EditorGUIUtility.singleLineHeight * 0.2f);

                    EditorGUI.LabelField(rect, label, EditorStyles.boldLabel);
                    NaughtyEditorGUI.BeginBoxGroup_Layout();
                }

                //Move to first child
                SerializedProperty child = property.Copy();
                child.Next(true);

                SerializedProperty endProperty = property.GetEndProperty(true);

                bool enterChildren;
                if (attribute.ShowHeaderAndBox)
                {
                    enterChildren = EditorGUILayout.PropertyField(child);
                }
                else
                {
                    enterChildren = EditorGUI.PropertyField(rect, child);
                }

                while (child.Next(enterChildren) && !SerializedProperty.EqualContents(child, endProperty))
                {
                    enterChildren = EditorGUILayout.PropertyField(child);
                }

                if (attribute.ShowHeaderAndBox)
                {
                    NaughtyEditorGUI.EndBoxGroup_Layout();
                }
            }
            else
            {
                EditorGUILayout.PropertyField(property);
                NaughtyEditorGUI.HelpBox_Layout("Can't use [Inline] on a property with no children.", MessageType.Warning);
            }
        }
        public override void OnInspectorGUI_PingArea()
        {
            serializedObject.Update();

            bool excludedRigManager = GameplayIngredientsSettings.currentSettings.excludedeManagers.Any(s => s == "RigManager");

            if (excludedRigManager)
            {
                EditorGUILayout.HelpBox("This Rig depends on the Rig Manager which is excluded in your Gameplay Ingredients Settings. This rig component will be inactive unless the manager is not excluded.", MessageType.Error, true);
                if (GUILayout.Button("Open Settings"))
                {
                    Selection.activeObject = GameplayIngredientsSettings.currentSettings;
                }
            }

            EditorGUI.BeginDisabledGroup(excludedRigManager);

            EditorGUI.BeginChangeCheck();

            DrawBreadCrumb("Rig", color, () =>
            {
                GUILayout.Label(ObjectNames.NicifyVariableName(serializedObject.targetObject.GetType().Name), GUILayout.ExpandWidth(true));

                OpenIngredientsExplorerButton(serializedObject.targetObject as Rig);
            });

            using (new GUILayout.VerticalScope(EditorStyles.helpBox, GUILayout.ExpandWidth(true)))
            {
                GUILayout.Label("Rig Update Properties", EditorStyles.boldLabel);
                using (new EditorGUI.IndentLevelScope(1))
                {
                    NaughtyEditorGUI.PropertyField_Layout(m_UpdateMode, true);
                    NaughtyEditorGUI.PropertyField_Layout(m_RigPriority, true);
                }
            }

            DrawBaseProperties();

            if (EditorGUI.EndChangeCheck())
            {
                serializedObject.ApplyModifiedProperties();
            }

            EditorGUI.EndDisabledGroup();
        }
    protected void DrawBaseProperties(params string[] excludedNames)
    {
        EditorGUILayout.Space();

        using (new EditorGUI.IndentLevelScope(1))
        {
            foreach (var prop in baseProperties)
            {
                if (excludedNames.Any(o => o == prop.name))
                {
                    continue;
                }
                NaughtyEditorGUI.PropertyField_Layout(prop, true);
            }
        }

        DrawButtons();
    }
예제 #26
0
        void WarnAgainstPositionWithoutRotation()
        {
            bool hasInvalidBones = false;

            if (serializedObject.FindProperty("globalPositionAlpha").floatValue > 0 && serializedObject.FindProperty("globalRotationAlpha").floatValue <= 0)
            {
                hasInvalidBones = true;
            }

            if (!hasInvalidBones)
            {
                bonesWithNonZeroPositionMatchingOverride.Clear();

                SerializedProperty posOverrides = serializedObject.FindProperty("positionMatchingOverrides");
                SerializedProperty rotOverrides = serializedObject.FindProperty("rotationMatchingOverrides");

                for (int i = 0; i < posOverrides.arraySize; i++)
                {
                    SerializedProperty posOverride = posOverrides.GetArrayElementAtIndex(i);
                    if (posOverride.FindPropertyRelative("alpha").floatValue > 0)
                    {
                        bonesWithNonZeroPositionMatchingOverride.Add(posOverride.FindPropertyRelative("bone.name").stringValue);
                    }
                }

                for (int i = 0; i < rotOverrides.arraySize; i++)
                {
                    SerializedProperty rotOverride = rotOverrides.GetArrayElementAtIndex(i);
                    bool boneHasPosOverride        = bonesWithNonZeroPositionMatchingOverride.Contains(rotOverride.FindPropertyRelative("bone.name").stringValue);
                    if (boneHasPosOverride && rotOverride.FindPropertyRelative("alpha").floatValue <= 0)
                    {
                        hasInvalidBones = true;
                        break;
                    }
                }
            }

            if (hasInvalidBones)
            {
                NaughtyEditorGUI.HelpBox_Layout("Position Matching with no Rotation Matching can produce horrifying results. \n" +
                                                "To avoid this, make sure that no bone has a Position Alpha over 0 and a Rotation Alpha of 0.", MessageType.Warning, logToConsole: false);
            }
        }
        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {
            MinMaxRange.SliderAttribute attribute = PropertyUtility.GetAttribute <MinMaxRange.SliderAttribute>(property);

            if (attribute != null)
            {
                Draw(position, property, attribute.min, attribute.max, label);
            }
            else
            {
                EditorGUI.PropertyField(position, property, label);
                if (property.isExpanded)
                {
                    EditorGUI.indentLevel++;
                    NaughtyEditorGUI.HelpBox_Layout("MinMaxRange needs a [MinMaxRange.Slider(min, max)] attribute for the fancy editor.", MessageType.Info);
                    EditorGUI.indentLevel--;
                }
            }
        }
예제 #28
0
        public void DrawDefaultPropertyAndHelpBox(Rect rect, SerializedProperty property, string message, MessageType messageType)
        {
            float indentLength = NaughtyEditorGUI.GetIndentLength(rect);
            Rect  helpBoxRect  = new Rect(
                rect.x + indentLength,
                rect.y,
                rect.width - indentLength,
                GetHelpBoxHeight());

            NaughtyEditorGUI.HelpBox(helpBoxRect, message, MessageType.Warning, context: property.serializedObject.targetObject);

            Rect propertyRect = new Rect(
                rect.x,
                rect.y + GetHelpBoxHeight(),
                rect.width,
                GetPropertyHeight(property));

            EditorGUI.PropertyField(propertyRect, property, true);
        }
        public override void OnInspectorGUI_PingArea()
        {
            serializedObject.Update();

            EditorGUI.BeginChangeCheck();

            DrawBreadCrumb("Action", color, () =>
            {
                NaughtyEditorGUI.PropertyField_Layout(m_Name, true);
                OpenIngredientsExplorerButton(serializedObject.targetObject as ActionBase);
            });

            DrawBaseProperties("Name");

            if (EditorGUI.EndChangeCheck())
            {
                serializedObject.ApplyModifiedProperties();
            }
        }
        void ValidateNoDuplicatePairs()
        {
            bool hasDuplicates = false;

            duplicatePairValidationSet.Clear();

            foreach (SerializedProperty pair in bonePairsList.serializedProperty)
            {
                if (!duplicatePairValidationSet.Add(CreateBonePairFromPairProperty(pair)))
                {
                    hasDuplicates = true;
                    break;
                }
            }

            if (hasDuplicates)
            {
                NaughtyEditorGUI.HelpBox_Layout("There are duplicate pairs.", MessageType.Warning);
                SetIsNotValid();

                if (GUILayout.Button("Fix"))
                {
                    Fix();
                }
            }


            void Fix()
            {
                duplicatePairValidationSet.Clear();

                for (int i = 0; i < bonePairsList.serializedProperty.arraySize; i++)
                {
                    SerializedProperty pair = bonePairsList.serializedProperty.GetArrayElementAtIndex(i);

                    if (!duplicatePairValidationSet.Add(CreateBonePairFromPairProperty(pair)))
                    {
                        bonePairsList.serializedProperty.DeleteArrayElementAtIndex(i);
                        i--;
                    }
                }
            }
        }