What's the correct way to update a property inside the editor dynamically with C#?

Godot Version

v4.3.stable.mono.official [77dcf97d8]

Question

I have a dialogue system I wrote myself, but I’m having trouble making one part of it more simple. I have a resource which contains the following 3 properties:

  • A SpriteFrame resource
  • A string resource to selecting an animation
  • A color resource for the text

What I’m trying to achieve here is the following:
When the SpriteFrame resource is changed, I want to dynamically update the string field to be a dropdown field, where the developers can pick one item from a list of available options. These options should be pulled from the SpriteFrame resource (as I believe it has a GetAnimationNames function).

What’s the correct way of achieving this behavior, as I found very little documentation explaining this.

edit: not the answer

Doesn’t explain what I’m trying to a achieve, as I’m not sure how to dynamically update a property. I’m aware that an enum works, but I don’t see anywhere on that page how to dynamically update said dictionary or enum every time a different property is changed.

ok i misunderstood, sorry about that. below is probably not the answer you are looking for so i am blurring it.

using Godot;
using System;
[GlobalClass]
public partial class CsharpTemp:Node {
	void SpriteResourceChanged() {
		GD.Print("changed");
	}
	public CsharpTemp() {
		sprite_frame_test v_test = new sprite_frame_test();
		v_test.Changed += SpriteResourceChanged;
		v_test.my_number = 99;
	}
}
public partial class sprite_frame_test:SpriteFrames {
	int m_number = 0;
	[Export]
	public int my_number {
		get {
			GD.Print("get=", m_number);
			return m_number;
		}
		set {
			m_number = value;
			EmitChanged();
			GD.Print("set=", m_number);
		}
	}
}

Resource — Godot Engine (stable) documentation in English

using Godot;

namespace Predation.Scripts.Resources;

[Tool]
[GlobalClass]
public partial class DialogueCharacter : Resource
{
    [Export]
    public SpriteFrames SpriteFrames { get; set; }
    
    
    [Export(PropertyHint.Enum)]
    public string AnimationName { get; set; }
    

    [Export]
    public Color TextColor;
}

This is what my resource looks like at the moment, and in the editor, it looks like this:
image

I’m trying to get the following behavior:
When I select a Sprite Frame resource to the very first property, I want my script (which is running inside the editor as well) to update the second property called Animation Name, and make it so I see the same list of animations that the First peroperty (SpriteFrame) contains.
These:
image

And be able to select ONE animation that I’d like to use for that specific resource.

did you try use _GetPropertyList() ?

1 Like

After many painful tries and fixing issues (Turns out the Example code shown on the official 4.3 godot docs for the C# code for _GetPropertyList was incorrect in a few places), I finally got the solution I wanted, in case anyone in the future needs something like this, this is how I achieved it:

using Godot;
using Godot.Collections;
using Array = System.Array;

namespace GameName.Scripts.Resources;

[Tool]
[GlobalClass]
public partial class DialogueCharacter : Resource
{
    [Export]
    public Color TextColor { get; set; }
    
    private SpriteFrames _spriteFrames;
    [Export]
    public SpriteFrames SpriteFrames {
        get => _spriteFrames;
        set
        {
            _spriteFrames = value;
            NotifyPropertyListChanged();
        }
    }
    
    private string[] _animations;
    private int _currentlySelected;

    public override Array<Dictionary> _GetPropertyList()
    {
        Array<Dictionary> properties = new();
        _animations = null;

        if (SpriteFrames is null) 
            return base._GetPropertyList();
        
        _animations = SpriteFrames.GetAnimationNames();

        if (_animations.Length == 0) 
            return base._GetPropertyList();
        
        string animationsString = _animations.Join(",");

        properties.Add(new Dictionary
        {
            { "name", "dialogueAnimations" },
            { "type", (int)Variant.Type.String },
            { "hint", (int)PropertyHint.Enum },
            { "hint_string", animationsString }
        });

        return properties;
    }

    public override Variant _Get(StringName property)
    {
        string propertyName = property.ToString();
        if (propertyName != "dialogueAnimations" || _animations == null)
            return default;
        
        return _animations[_currentlySelected];
    }

    public override bool _Set(StringName property, Variant value)
    {
        string propertyName = property.ToString();
        if (propertyName != "dialogueAnimations" || _animations == null)
            return false;
        
        int index = Array.IndexOf(_animations, value.ToString());
        if (index == -1) return false;
        
        _currentlySelected = index;
        return true;

    }
}
1 Like