Export_custom nested typed collections, hint_string and enum

Godot Version

v4.6.stable.official [89cea1439]

Question

I want to export a Dictionary whose keys are members of an enum and whose values are Arrays of Resources.

extends Node

#D_allows is a Dictionary of things allowed by the Item
enum D_allow_key {
NATIVE_DAMAGE_ATTR,
NATIVE_TO_HIT_ATTR,
DAMAGE_TYPE
}
@export var D_allows : Dictionary[D_allow_key,Array] = {}

The key being typed to my enum works well. Now I want to type the valueArray, because without a type, I can’t select/drag a Custom Resource to the value :

The direct approach faces the ‘Nested typed collections are not supported’ error :

@export var D_allows2 : Dictionary[D_allow_key,Array[Resource]] = {}

export nested typed collection issue 3

Reading Lindbrum, I tried to use @export_custom with a hint_string :

@export_custom(PROPERTY_HINT_DICTIONARY_TYPE, “int:D_allow_key;28:24/17:Resource”) var D_allows : Dictionary[D_allow_key,Array] = {}

But I can’t find the Variant.Type for enums in the list because enums are no Variant (see below : it works with TYPE_INT and PROPERTY_HINT_ENUM, “4/2”). I put in an int in the example above to ensure I can drag a Resource into the nested Array : I can !

I tried to circumvent the problem by defining an enum property as explained by Leif in the Wind.


@export_custom(PROPERTY_HINT_DICTIONARY_TYPE, str(“%d:%d/%d:” + D_allow_key_list) % [TYPE_ARRAY, TYPE_INT, PROPERTY_HINT_ENUM] + “:D_allow_key;28:24/17:Resource”) var D_allows : Dictionary[D_allow_key,Array] = {}

Problem is, the second argument of @export_custom must not only be a String, but also a constant :

So I went and typed the whole thing literally :

@export_custom(PROPERTY_HINT_DICTIONARY_TYPE, “4/2:NATIVE_DAMAGE_ATTR,NATIVE_TO_HIT_ATTR,DAMAGE_TYPE;28:24/17:Resource”) var D_allows : Dictionary[D_allow_key,Array] = {}

It works !

Problem is, now I lost the benefit of having an enum in the first place. I have to type in every new value of D_allow_key in the @export_custom hint_string.

Everything seems to be in place, except the hint_string of @export_custom won’t accept variables, even if they evaluate to Strings, and it cannot defer the hint to the typed definition placed after the variable declaration (where Dictionary[D_allow_key,Array] = {} actually hints to the D_allow_key enum members).

I could go and try to write the whole \_get\_property_list() like Leif in the Wind, but I would like to know beforehand whether/why @export_custom can’t offer the functionality I’m looking for.

Any clever way to go about this without tripping again into a five-hour ‘eadbang is also welcome.

I spent months banging my head against exporting Enums before realizing it was limiting for architectural reasons for me.

I would personally probably solve this by making it an Array of Resources and just put the Enum as the first value of the Resource. Then I would code in the lookup by Enum and only allowing a single Enum. Because I think it would be easier than what you are doing.

Either that or I would use a Dictionary[String, Array] and convert between the Enum and String in my code.

1 Like

So I went and typed the whole thing literally :

@export_custom(PROPERTY_HINT_DICTIONARY_TYPE, “4/2:NATIVE_DAMAGE_ATTR,NATIVE_TO_HIT_ATTR,DAMAGE_TYPE;28:24/17:Resource”) var D_allows : Dictionary[D_allow_key,Array] = {}

It works !

export nested typed collection issue 5

No it doesn’t.

Hitting “Add Key/Value Pair” on the D_allows Dictionary crashes the Godot engine to the desktop, whether I filled New Key, New Value, both or none. No error window, no Windows error window, no message in log (I don’t even run the project).

Trying to reproduce in a closed test to declare the crash now.

For dynamic properties like this you can use Object._validate_property()

Example:

@tool
extends Node


enum MyEnum {
	Value1, Value2, Value3
}


@export var dict: Dictionary[MyEnum, Array]


func _validate_property(property: Dictionary) -> void:
	if property.name == "dict":
		property.hint_string = "{key_type}/{key_hint}:{key_hint_string};{array_type}:{value_type}/{value_hint}:{value_hint_string}".format({
			key_type = TYPE_INT,
			key_hint = PROPERTY_HINT_ENUM,
			key_hint_string = ",".join(MyEnum.keys()),
			array_type = TYPE_ARRAY,
			value_type = TYPE_OBJECT,
			value_hint = PROPERTY_HINT_RESOURCE_TYPE,
			value_hint_string = "Texture2D"
		})
2 Likes

For dynamic properties like this you can use Object._validate_property()

Well, it does work, and it’s a bit shorter and more elegant way to do it than the whole \_get\_property_list, even for one property.

Still, I wish @export_custom would reach the same result without a hitch. It seems… more straightforward than declaring an @export then going over it.

I’m going to go and mark it as a solution, just because @export_custom doesn’t seem to be on par with the property functions yet, and because it does solve my problem.

Hitting “Add Key/Value Pair” on the D_allows Dictionary crashes the Godot engine to the desktop, whether I filled New Key, New Value, both or none. No error window, no Windows error window, no message in log (I don’t even run the project).

For later reference, this didn’t happen because I entered “4/2” for “TYPE_STRING/PROPERTY_HINT_ENUM” instead of “2/2” for “TYPE_INT/PROPERTY_HINT_ENUM”.

Couldn’t reproduce the crash changing it. It gives the error

ERROR: Attempted to use operator[] a variable of type ‘String’ into a TypedDictionary.Key of type ‘int’.