0
\$\begingroup\$

I made a PropertyDrawer for a simple class, which looks something like this:

public class Limiter {
    public enum LimitType { None = 0, Range = 1, Vector = 2 }
    public LimitType limit;
    public Range range; //details of 'Range' are not really relevant.
    [VectorPicker] public Vector2 vector;

    /* other stuff */
}
[CustomPropertyDrawer(typeof(Limiter))]
LimiterProperty : PropertyDrawer {
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {

        /* other stuff */

        if(/* main property is expanded */) {
            SerializedProperty _limit = property.FindPropertyRelative("limit");
            position = AddProperty(position, _limit); //moves the rectangle into position for this property
            EditorGUI.PropertyField(position, _limit, new GUIContent("Type of limiter on the position."));

            if(_posLim.enumValueIndex == 1) {
                SerializedProperty _range = property.FindPropertyRelative("range");
                position = AddProperty(position, _range);
                EditorGUI.PropertyField(position, _range, new GUIContent("Range"), true);
            }

            if(_posLim.enumValueIndex == 2) {
                SerializedProperty _posVector = property.FindPropertyRelative("vector");
                position = AddProperty(position, _posVector);
                Debug.Log("Before: " + _posLim.enumValueIndex);
                EditorGUI.PropertyField(position, _posVector, new GUIContent("Position Vector"));
                Debug.Log("After: " + _posLim.enumValueIndex);
            }

            /* other stuff */

        }
    }
}

See the Debug.Log("Before" + enum); and Debug.Log("After" + enum);? This is what they print when I change the enumerator to "Vector".

Image of the log.

It immediately changes back. If it was on "Vector" already, then it can be changed to "None" or "Range" just fine, but can't be changed back. There are also no problems switching between "None" and "Range".

Here's the VectorPicker:

[CustomPropertyDrawer(typeof(VectorPickerAttribute))]
public class VectorPickerDrawer : PropertyDrawer {
    #region Variables
    bool _trackMouse;
    SerializedProperty _property;
    MonoBehaviour script;

    ///<summary>Keep the currently selected object to avoid loosing focus while/after tracking</summary>
    GameObject _mySelection;

    ///<summary>For reverting if tracking canceled</summary>
    Vector2 _originalPosition;

    ///<summary>Flag for doing Setup only once</summary>
    bool _setup;

    /// <summary>Mouse position from scene view into the world.</summary>
    Vector2 worldPoint;
    #endregion

    /// <summary>
    /// Catch a click event while over the SceneView
    /// </summary>
    /// <param name="sceneView">The current scene view => might not work anymore with multiple SceneViews</param>
    private void UpdateSceneView(SceneView sceneView) {

        Camera cam = SceneView.lastActiveSceneView.camera;
        worldPoint = Event.current.mousePosition;
        worldPoint.y = Screen.height - worldPoint.y - 36.0f; // ??? Why that offset?!
        worldPoint = cam.ScreenToWorldPoint(worldPoint);

        VectorPickerAttribute vectorPicker = attribute as VectorPickerAttribute;
        if(script != null && vectorPicker.relative) worldPoint -= (Vector2)script.transform.position;

        // get current event
        var e = Event.current;

        // Only check while tracking
        if(_trackMouse) {
            if((e.type == EventType.MouseDown || e.type == EventType.MouseUp) && e.button == 0) {
                OnTrackingEnds(false, e);
            }
            else {
                // Prevent losing focus
                Selection.activeGameObject = _mySelection;
            }
        }
        else {
            // Skip if event is Layout or Repaint
            if(e.type == EventType.Layout || e.type == EventType.Repaint) return;

            // Prevent Propagation
            Event.current.Use();
            Event.current = null;

            // Unlock Inspector
            ActiveEditorTracker.sharedTracker.isLocked = false;

            // Prevent losing focus
            Selection.activeGameObject = _mySelection;

            // Remove SceneView callback
            SceneView.onSceneGUIDelegate -= UpdateSceneView;

        }
    }

    /// <summary>
    /// Called when ending Tracking
    /// </summary>
    /// <param name="revert">flag whether to revert to previous value or not</param>
    /// <param name="e">event that caused the ending</param>
    /// <returns>Returns the vector value of the property that we are modifying.</returns>
    private Vector2 OnTrackingEnds(bool revert, Event e) {
        e.Use();
        Event.current = null;
        //Debug.Log("Vector Picker finished");

        if(revert) {
            // restore previous value
            _property.vector2Value = _originalPosition;
            //Debug.Log("Reverted");
        }

        // disable tracking
        _trackMouse = false;

        // Apply changes
        _property.serializedObject.ApplyModifiedProperties();

        return _property.vector2Value;
    }

    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
        script = (MonoBehaviour)property.serializedObject.targetObject;

        if(property.propertyType != SerializedPropertyType.Vector2) {
            EditorGUI.HelpBox(position, "This Attribute requires Vector2", MessageType.Error);
            return;
        }

        var e = Event.current;

        if(!_setup) {
            // store the selected Object (should be the one with this drawer active)
            _mySelection = Selection.activeGameObject;
            _property = property;

            _setup = true;
        }


        // load current value into serialized properties
        _property.serializedObject.Update();

        //specific to the ONE property we are updating
        bool trackingThis = _trackMouse && property.propertyPath == _property.propertyPath;

        GUI.enabled = !trackingThis;
        EditorGUI.PropertyField(position, property, label);
        GUI.enabled = true;


        // Write manually changed values to the serialized fields
        _property.serializedObject.ApplyModifiedProperties();



        if(!trackingThis) {
            var button = new Rect(position) {
                x = position.width - 2,
                width = position.height
            };

            // if button wasn't pressed do nothing
            if(!GUI.Button(button, "")) return;

            // store current value in case of revert
            _originalPosition = _property.vector2Value;

            // enable tracking
            _property = property;
            _trackMouse = true;

            // Lock the inspector so we cannot lose focus
            ActiveEditorTracker.sharedTracker.isLocked = true;

            // Prevent event propagation
            e.Use();

            //Debug.Log("Vector Picker started");
            return;
        }

        // <<< This section is only reached if we are in tracking mode >>>

        // Overwrite the onSceneGUIDelegate with a callback for the SceneView
        SceneView.onSceneGUIDelegate = UpdateSceneView;

        // Set to world position
        _property.vector2Value = worldPoint;

        // Track position until either Mouse button 0 (to confirm) or Escape (to cancel) is clicked
        var mouseUpDown = (e.type == EventType.MouseUp || e.type == EventType.MouseDown) && e.button == 0;
        if(mouseUpDown) {
            // End the tracking, don't revert
            property.vector2Value = OnTrackingEnds(false, e);
        }
        else if(e.type == EventType.KeyUp && _trackMouse && e.keyCode == KeyCode.Escape) {
            // Cancel tracking via Escape => revert value
            property.vector2Value = OnTrackingEnds(true, e);
        }

        property.serializedObject.ApplyModifiedProperties();

        //This fixes "randomly stops updating for no reason".
        EditorUtility.SetDirty(property.serializedObject.targetObject);
    }
}

When I remove VectorPicker from Limiter, it works fine. I have no idea what could be causing this.

\$\endgroup\$
1
\$\begingroup\$

I was able to fix it. Turns out it was this stuff that was causing it:

_property.serializedObject.Update();
_property.serializedObject.ApplyModifiedProperties();
\$\endgroup\$
1
  • \$\begingroup\$ This was my problem, but not exactly as is. I called Update before anything else and apply at the end and some changes where always resetted, but after removing the call to Update it worked. \$\endgroup\$
    – Forestrf
    Jan 12 '20 at 2:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.