С# - User resource is not displayed in the editor

Godot Version 4.4 Stable

Question

I wrote the resource code with the [GlobalClass] attribute, then built the project (clicked the hammer) and still the resource is not displayed. What can I do?

using Godot;

namespace Game.Resources
{
    [GlobalClass]
    public partial class HealthData : Resource // Data for saving and loading
    {
        [Export] public float RevivalHealth { get; set; }
        [Export] public float SavedHealth { get; set; }
        [Export] public bool Immortality { get; set; }
    }
}

namespace Game.Components
{
    using Game.Resources;
    public partial class HealthInfo : RefCounted // Data when health changes
    {
        public float CurrentHealth;
        public float PreviousHealth;

        public float HealthDelta => CurrentHealth - PreviousHealth;
        public bool IsDamage => HealthDelta < 0;
        public bool IsHeal => HealthDelta > 0;
    }

    public partial class HealthComponent : Node3D
    {
        // SIGNALS

        [Signal] public delegate void HealthChangedEventHandler(HealthInfo info);
        [Signal] public delegate void DiedEventHandler();

        // EXPORTED DATA

        [Export] private HealthData _data_resource; // Data is saved and loaded from the same file

        // CONSTANTS

        private const float MINIMUM_POSSIBLE_HEALTH = 1.0f;
        private const float MAXIMUM_POSSIBLE_HEALTH = 10000.0f; // There may be a change
        private const float CRITICAL_HEALTH_RATIO = 0.2f;

        // FIELDS AND PROPERTIES

        private float _revival_health; // The current name is better than "_max_health"
        public float RevivalHealth
        {
            get
            {
                return _revival_health;
            }
            private set
            {
                _revival_health = Mathf.Clamp(value, MINIMUM_POSSIBLE_HEALTH, MAXIMUM_POSSIBLE_HEALTH);
            }
        }

        private float _current_health;
        public float CurrentHealth
        {
            get
            {
                return _current_health;
            }
            private set
            {
                if (Mathf.IsEqualApprox(_current_health, value)) return;

                HealthInfo info = new HealthInfo();
                info.CurrentHealth = Mathf.Clamp(value, 0.0f, _revival_health);
                info.PreviousHealth = CurrentHealth;

                EmitSignal(SignalName.HealthChanged, info);

                if (info.CurrentHealth == 0 && IsMortal)
                {
                    EmitSignal(SignalName.Died);
                }

                if (IsMortal)
                {
                    _current_health = info.CurrentHealth;
                }
            }
        }

        private bool _immortality;

        // STATE CHECK PROPERTIES

        public bool IsAlive => CurrentHealth > 0.0f;
        public bool IsDead => !IsAlive;
        public bool IsImmortal => _immortality;
        public bool IsMortal => !IsImmortal;
        public bool IsHealthFull => Mathf.IsEqualApprox(CurrentHealth, RevivalHealth);
        public bool IsCriticalHealth => CurrentHealth <= RevivalHealth * CRITICAL_HEALTH_RATIO;
        public bool IsDamaged => CurrentHealth < RevivalHealth;
        public bool CanBeHealed => IsDamaged && IsAlive;
        public string CurrentHealthText => $"{CurrentHealth:F0}";
        public string RevivalHealthText => $"{RevivalHealth:F0}";

        // OVERRIDED FUNCTIONS

        public override void _Ready()
        {
            Load(); // There may be a change
        }

        // FUNCTIONS

        public void Heal(float heal)
        {
            if (heal < 0.0f)
            {
                GD.PushWarning("The value of the Heal() function must be positive. The passed value was converted to a positive value.");
                CurrentHealth += Mathf.Abs(heal);
                return;
            }
            CurrentHealth += heal;
        }
        public void Damage(float damage)
        {
            if (damage < 0.0f)
            {
                GD.PushWarning("The value of the Heal() function must be positive. The passed value was converted to a positive value.");
                CurrentHealth += Mathf.Abs(damage);
                return;
            }
            CurrentHealth -= damage;
        }
        public void Save()
        {
            HealthData data = new HealthData();

            data.RevivalHealth = RevivalHealth;
            data.SavedHealth = CurrentHealth;
            data.Immortality = _immortality;

            Error e = ResourceSaver.Save(data, _data_resource.ResourcePath, ResourceSaver.SaverFlags.None);

            if (e != Error.Ok)
            {
                GD.PrintErr("Error when saving a file (", _data_resource.ResourcePath, ").");
            }
        }
        public void Load()
        {
            HealthData data = ResourceLoader.Load<HealthData>(_data_resource.ResourcePath, "HealthData", ResourceLoader.CacheMode.Ignore);
            if (data == null)
            {
                GD.PrintErr("Error when opening a file (", _data_resource.ResourcePath, ").");
                return;
            }
            RevivalHealth = data.RevivalHealth;
            CurrentHealth = data.SavedHealth;
            _immortality = data.Immortality;
        }
    }
}

Your properties need to have a getter and a setter, so this would be correct:

using Godot;

namespace Game.Resources
{
    [GlobalClass]
    public partial class HealthData : Resource // Data for saving and loading
    {
        [Export] public float RevivalHealth { get; set; }
        [Export] public float SavedHealth { get; set; }
        [Export] public bool Immortality { get; set; }
    }
}

It didn’t work for me

While using properties is better (or at least ‘best practice’), it is not required.

Were you able to build the project successfully? Did you get some output in MSBuild at the bottom?

I see you updated your code. You need to put the resource in its own file.

1 Like

No errors, except that the resource was not loaded into the variable that stores it (_data_resource in HealthComponent).

Thanks, that helped.