dbrizov / NaughtyAttributes

Attribute Extensions for Unity
MIT License
4.57k stars 465 forks source link

Make RuntimeReadOnly Attribute which works on fields and properties #391

Closed radomirbrkic closed 2 months ago

radomirbrkic commented 2 months ago

How to implement Runtime ReadOnly attribute?

First of all, thank you for the awesome NaughtyAttributes library! It has been very useful in my Unity projects.

I am currently trying to implement a custom RuntimeReadOnly attribute, which would make fields and properties read-only in the Unity Inspector when the game is running (i.e., in play mode). I am wondering if there is a recommended way to do this using NaughtyAttributes.

Here’s a basic idea of what I’m aiming for:

The field or property should be editable in Edit Mode. The field should become read-only when the game is in Play Mode. So far, I’ve tried implementing a basic RuntimeReadOnlyAttribute and a PropertyDrawer:

[CustomPropertyDrawer(typeof(RuntimeReadOnlyAttribute))] public class RuntimeReadOnlyDrawer : PropertyDrawer { public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { EditorGUI.BeginProperty(position, label, property);

    // Reserve space for the label and the property field
    position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);

    using(new EditorGUI.DisabledScope(Application.isPlaying))
    {
        EditorGUI.PropertyField(position, property, GUIContent.none);
    }

    EditorGUI.EndProperty();
}

}

However, this doesn't disable + and - buttons in inspector for list/array (just disables elements) and it doesn't work on properties but only on fields only, which is biggest problem I have run into. I have getter properties like this

public float Next => Last + interval;

Any guidance or advice on how to approach this would be greatly appreciated!

Thank you in advance.

TylerTemp commented 2 months ago

To do this you need an Editor level component, not PropertyDrawer.

And why re-create the wheel?

I have a project that do the things as describe:

using SaintsField;
using SaintsField.Playa;

// these two can be used together with NaughtAttribute:
// disable field
[DisableIf(EMode.Play)]   // or [EnableIf(EMode.Edit)]
public int field;
// disable property
[field: SerializeField, DisableIf(EMode.Play)]    // or [EnableIf(EMode.Edit)]
public int prop { get; private set; }

// however, to use this you'll need to give-up on NaughtyAttribute:
// disable array/list
[PlayaDisableIf(EMode.Play)]     // or [PlayaEnableIf(EMode.Edit)]
public int[] array;

Edit Mode:

image

Play Mode:

image

If you don't like it, there are also Tri-Inspector that did the same thing.


Back to the question itself, if you need to implement it with NaughtyAttribute, have a look at NaughtyInspector. In the function of "DrawSerializedProperties", you will need to read-out your "RuntimeReadOnly", and disable the scoop there so it can work for a list/array, as Unity do not have a way to custom-draw a list/array outside an "UnityEditor.Editor" level.

radomirbrkic commented 2 months ago

Ok, thanks for alternative repositories. Since I have no questions, I will close issue