Adding array's of a custom class in _get_property_list()

Godot Version

4.7.beta1.mono

Question

I’m trying to add an array of resources to my inspector properties when a certain condition is met.The conditional portions are working great, but specifically when trying to get the editor to handle an array of custom resources I’m struggling to get a functional result. Currently, the editor shows the following, non-functional field:
image

The relevant code is below:

var acquisition_conditions: Array[TargetCondition]

...
func _get_property_list() -> Array[Dictionary]:
  ...
  if acquisition_rule == AcquisitionRule.N_CONDITION:
	props.append({
		"name": &"acquisition_conditions",
		"type": TYPE_ARRAY,
		"usage": PROPERTY_USAGE_DEFAULT,
		"hint": PROPERTY_HINT_TYPE_STRING,
		"hint_string": "%d/%d:%s" % [
			TYPE_OBJECT,
			PROPERTY_HINT_RESOURCE_TYPE,
			"TargetCondition"
		],
	})

Any insight would be appreciated, thank you!

You need to implement getter/setter methods as well. The engine needs some data source for the property. You might want to use a different name for the actual array.

Through some extra experimentation I found that this functions when the type of the array is Array[Object] instead. Can you provide more information into what you’re suggesting with the getters and setters. Like having an Array[Object] variable masking the actual Array[TargetCondition], and using the combination of the two to achieve type safety behind the inspector?

Sorry, to amend this, the type was set to Array[String], not Array[Object].

@tool
extends Node

var my_prop_data: Array[MyResource] = []

func _set(prop, value) -> bool:
	if prop == &"my_prop":
		my_prop_data = value
		return true
	return false
	
func _get(prop) -> Variant:
	if prop == &"my_prop":
		return my_prop_data
	return null
	
func _get_property_list() -> Array[Dictionary]:
	return[{
		"name": &"my_prop",
		"type": TYPE_ARRAY,
		"usage": PROPERTY_USAGE_DEFAULT,
		"hint": PROPERTY_HINT_TYPE_STRING,
		"hint_string": "%d/%d:%s" % [
			TYPE_OBJECT,
			PROPERTY_HINT_RESOURCE_TYPE,
			"MyResource"
		],
	}]

Creating _get and _set doesn’t seem to make any difference, unless I’m supposed to do some processing on the data itself inside.

For clarification, the issue only exists with arrays, I’m able to directly reference properties and have it function outside of those arrays. For example:

var range_type: RangeType
var range_area: NodePath
var range_area_node: Area3D
var range_float: float

   ...
		props.append({
			"name": &"range_type",
			"type": TYPE_INT,
			"usage": PROPERTY_USAGE_DEFAULT
					|PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED
					|PROPERTY_USAGE_CLASS_IS_ENUM,
			"hint": PROPERTY_HINT_ENUM,
			"hint_string": ",".join(RangeType.keys())
		})
		if range_type == RangeType.AREA3D:
			props.append({
				"name": &"range_area",
				"type": TYPE_NODE_PATH,
				"usage": PROPERTY_USAGE_DEFAULT,
				"hint": PROPERTY_HINT_NODE_PATH_VALID_TYPES,
				"hint_string": "Area3D",
			})
		if range_type == RangeType.FLOAT:
			props.append({
				"name": &"range_float",
				"type": TYPE_FLOAT,
				"usage": PROPERTY_USAGE_DEFAULT,
				"hint": PROPERTY_HINT_RANGE,
				"hint_string": "0,50,0.1",
			})

These function, but the node itself cannot be passed directly to the variable, and I’ve opted to simply resolve that at run time.

I suppose I’ve just inadvertantly answered my own question here, and I also need to resolve the resources independently of how I’m setting them in the inspector fields.

EDIT: If I understand correctly, what you’re suggesting is to resolve it and assign it to the typed variable in a setter, and to configure the getter to read it and convert it to a usable form for the inspector.

Try my example in isolation to see what is happening. It creates a virtual property with set/get interface whose actual data is kept in a variable that’s not directly exposed to the inspector. This is basically the same thing that’s demonstrated in _get_property_list() documentation precisely for handling cases like yours.

I tried your example in isolation and it didn’t function, so I assumed that it was just intended to convey the general idea. It doesn’t run as written on latest.

The example works in 4.6.
You might need to reload the scene.

I’m in 4.7, latest, not stable. _set wants a boolean to be returned.

Well return it.

I did. It still did not function.

There, I properly typed the example.
What do you mean by “not function”?

The behaviour is the same, I get a (Nil) Array[TargetCondition] that I’m unable to interact with in the inspector. I was previously following the documentation on the globals page that has examples for the TYPE_ARRAY enum. I’m going through the example on Object now to see if I can wrangle something functional.

The example works. Make sure everything is ok with your resource class.
Try with generic Resource first. You also might want to initialize the array variable: var my_prop_data: Array[MyResource] = []

Initializing the variable appears to have resolved it :melting_face:

1 Like