How to find property of a serializeObject that has the same name with a field of another property?

I had a custom attribute and property drawer class to show or hide field depends on some condition.
In the OnGui method of the drawer class, I would find a property and then do something with it.

    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        ShowWhenAttribute attribute = (ShowWhenAttribute)this.attribute;
        SerializedProperty conditionField = property.serializedObject.FindProperty(attribute.conditionFieldName);
        // Do something here
    }

I also had a serializable class and an instance of that class in a monobehaviour class.

public enum StatusType { Burn, Bleed, Poison, Freeze, Slow, Blind, Injured }

[System.Serializable]
public class State
{
    public StatusType type;
    public float duration;
    [ShowWhen("duration", /* For example: ">5" */)] public float percent;
    public int damage;
    public float timeBtwHits;
}

public class Item : MonoBehaviour
{
  public float duration;
  public State state;
}

The problem is the conditionField is not state.duration but duration. How to fix it?

Because you used property.serializedObject.FindProperty. So you accessed the SerializedObject (the root object that is actually serialized, in your case the Item class) and used FindProperty to find a property with that name. If you want to use a property on the “same level” you would need to find the property relative to the parent. Unfortunately the SerializedProperty class doesn’t have a GetParent method. However you can create by disecting the property path. Note that this of course has an edge case when you actually have a property inside the root object itself in which case there is no parent serialized property. So I quickly made this FindSiblingProperty extension method:

public static class SerializedPropertyExt
{
    public static SerializedProperty GetParent(this SerializedProperty aProperty)
    {
        var path = aProperty.propertyPath;
        int i = path.LastIndexOf('.');
        if (i < 0)
            return null;
        return aProperty.serializedObject.FindProperty(path.Substring(0, i));
    }
    public static SerializedProperty FindSiblingProperty(this SerializedProperty aProperty, string aPath)
    {
        var parent = aProperty.GetParent();
        if (parent == null)
            return aProperty.serializedObject.FindProperty(aPath);
        return parent.FindPropertyRelative(aPath);
    }
}

With those extension methods you can simply do

SerializedProperty conditionField = property.FindSiblingProperty("condition");

So we first look for a parent property and if there is none we just grab the property on the serialized object. Otherwise we look for the property relative to the parent.