How to make exported property readonly based on the value of another property?

Godot Version

v4.3.stable.mono.arch_linux

Question

Hi, I’m creating a custom Resource, and I have code like the following:

[GlobalClass, Tool]
public partial class AmmoData : Resource
{
    [Export]
    public ProjectileType ProjectileType { get; set; }

    [Export]
    public uint PelletCount { get; set; }

    public override void _ValidateProperty(Dictionary property)
    {
        if (property["name"].AsStringName() == PropertyName.PelletCount)
        {
            var propertyUsageFlags = property["usage"].As<PropertyUsageFlags>();
            
            if (ProjectileType == ProjectileType.Bullet)
            {
                propertyUsageFlags |= PropertyUsageFlags.ReadOnly;
            }
            else
            {
                propertyUsageFlags &= ~PropertyUsageFlags.ReadOnly;
            }
            
            property["usage"] = (int)propertyUsageFlags;
            base._ValidateProperty(property);
        }
    }
}

The logic behind this code is “if a user sets ProjectileType value to Bullet - make PelletCount readonly. Otherwise, allow a user to edit PelletCount”.

Provided code kinda works, but it checks properties and applies logic from _ValidateProperty only when code is rebuilt. I want this validation logic to be executed on every change of ProjectileType property (or on the change of any property of my resource).

1 Like

One of the ways to solve the problem is to call NotifyPropertyListChanged(); from the setter of ProjectileType property.

[GlobalClass, Tool]
public partial class AmmoData : Resource
{
	[Export]
	public ProjectileType ProjectileType
	{
		get => _projectileType;
		set
		{
			_projectileType = value;
			NotifyPropertyListChanged();
		}
	}

	[Export]
	public uint PelletCount { get; set; }

	public override void _ValidateProperty(Dictionary property)
	{
		if (property["name"].AsStringName() == PropertyName.PelletCount)
		{
			var propertyUsageFlags = property["usage"].As<PropertyUsageFlags>();
            
			if (ProjectileType == ProjectileType.Bullet)
			{
				propertyUsageFlags |= PropertyUsageFlags.ReadOnly;
			}
			else
			{
				propertyUsageFlags &= ~PropertyUsageFlags.ReadOnly;
			}
            
			property["usage"] = (int)propertyUsageFlags;
			base._ValidateProperty(property);
		}
	}
}
1 Like