Overriding _set in custom Stats resource class fails to find available index

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By danielmeridew

I am trying to expose array object properties in a dict via overriding _get and _set.

_get works as expected, although my _set fails to find the dict key which is definitely there.

stats.hp will retrieve the speed value.

stats.hp -= value will throw an index not found error.

See my Stats class below where I am creating a dict of my stat array based on enum names use to get/set stat properties simply:

class_name Stats extends Resource

@export var stats: Array[Stat] = []

var stats_dict: Dictionary = {}

func setup():
	for stat in stats:
		stats_dict[stat.Type.keys()[stat.type].to_lower()] = stat

func _get(name):
	if stats_dict.has(name):
		return stats_dict[name].value

func _set(name, value):
	if stats_dict.has(name):
		stats_dict[name].value = value

I have created Stats/Stat resources on my mob, and can _get them without issue, although when trying to _set them I receive an invalid set index error:

Invalid set index 'hp' (on base: 'Resource (Stats)') with value of type 'float'.

Debugging tells me the dictionary is available, and the appropriate key/value that I expect.

See my Stat class extract below that populates the Array[Stat]:

class_name Stat extends Resource

enum Type { SPEED, DAMAGE, HP, MAX_HP, XP, MAX_XP, MASS, SCALE, FREQUENCY, COOLDOWN, DURATION, PASSTHROUGH, RANGE, HOMING, KNOCKBACK }
enum Modifier { ADD, MULTIPLY }

@export var type: Type
@export var base_value: float
@export var value: float

var temporary_modifiers = []

func _init(_type: Type = Type.SPEED, _base_value: float = 0.0, _value: float = 0.0):
	self.type = _type
	self.base_value = _base_value
	self.value = _base_value
:bust_in_silhouette: Reply From: danielmeridew

Turns out a good nights sleep and a well phrased question to ChatGPT is all that is required, the solution to this problem is:

func _set(name: StringName, value: Variant) -> bool:
	if stats_dict.has(name):
		stats_dict[name].value = value
		return true
	else:
		return false

func _get(name: StringName) -> Variant:
	if stats_dict.has(name):
		return stats_dict[name].value
	else:
		return null

Because apparently:

In Godot 4, it is now expected that the _set function returns a boolean value. This is a change from previous versions of Godot where _set did not return anything.

The return value is used to indicate whether the property was successfully set or not. If _set returns true, it means that the property was recognized and set successfully. If it returns false, it indicates that the property was not recognized by your _set method. Godot will then try to set the property on any parent classes.

This can be helpful for error handling and debugging. For example, if you're trying to set a property and it's not being changed as expected, a false return value from _set could clue you into the fact that your code is trying to set a property that doesn't exist or is misspelled.

I’m not sure why I didn’t get an override definition error with my first implementation…