How to use the new export_custom in Godot 4.3?

Godot Version

4.3.stable

Question

Hi all, I’ve just reviewed the changes in 4.3, and it looks like there is a new export_custom function that we can use! Unfortunately, the changelog simply links to this github page which doesn’t really shed light on how to use it. I don’t see any real info on this in the docs, either (there is an entry, but it doesn’t provide an example of which I think there should be multiple). So, can anyone shed some light on how to use it?

To get the discussion started, here is an example of some custom properties I have set up in a tool script for an enemy spawner. These properties are used to set the amount and type of enemy types that can spawn. The reason there is so much code here is because I want my tool to show/hide the enemy_typeX variables in the inspector if enemy_type_quantity is less than X. It works well as-is, but I’m crossing my fingers that someone could rework what I provide into a cleaner solution with this new export_property thing. I have another case in my small project like this, and could see there being more as I continue development, and I figure I can apply what I learn here to each case.

With all this said, I may be completely misunderstanding what export_custom actually does, so if so, I’d still appreciate the confirmation on that or an explanation of what it actually is.

var enemy_type_quantity = range(1,5)
var enemy_type1: Enemy_Type
var enemy_type2: Enemy_Type
var enemy_type3: Enemy_Type
var enemy_type4: Enemy_Type
var enemy_type5: Enemy_Type

func _get_property_list() -> Array[Dictionary]:
	var ret: Array[Dictionary] = []
	
	ret.append({
		"name": "/enemy_type_quantity",
		"type": TYPE_INT,
		"hint": PROPERTY_HINT_RANGE,
		"hint_string": "1,5",
	if (enemy_type_quantity >= 1):
		ret.append({
			"name": "enemy_type1",
			"type": TYPE_INT,
			"hint": PROPERTY_HINT_ENUM,
			"hint_string": generate_enum_hint_string(),
			})
	if (enemy_type_quantity >= 2):
		ret.append({
			"name": "enemy_type2",
			"type": TYPE_INT,
			"hint": PROPERTY_HINT_ENUM,
			"hint_string": generate_enum_hint_string(),
			})
	if (enemy_type_quantity >= 3):
		ret.append({
			"name": "enemy_type3",
			"type": TYPE_INT,
			"hint": PROPERTY_HINT_ENUM,
			"hint_string": generate_enum_hint_string(),
			})
	if (enemy_type_quantity >= 4):
		ret.append({
			"name": "enemy_type4",
			"type": TYPE_INT,
			"hint": PROPERTY_HINT_ENUM,
			"hint_string": generate_enum_hint_string(),
			})
	if (enemy_type_quantity == 5):
		ret.append({
			"name": "enemy_type5",
			"type": TYPE_INT,
			"hint": PROPERTY_HINT_ENUM,
			"hint_string": generate_enum_hint_string(),
			})
	
	return ret


func generate_enum_hint_string() -> String:
	var ret: String = ""
	for k in Enemy_Type.keys():
		if not ret.is_empty():
			ret += ','
		ret += k
	
	return ret


func _set(prop_name: StringName, value) -> bool:
	var retval: bool = true
	
	match prop_name:
		"/enemy_type_quantity":
			enemy_type_quantity = value
			notify_property_list_changed()
		"enemy_type1":
			enemy_type1 = value
		"enemy_type2":
			enemy_type2 = value
		"enemy_type3":
			enemy_type3 = value
		"enemy_type4":
			enemy_type4 = value
		"enemy_type5":
			enemy_type5 = value
		_:
			retval = false
	
	return retval


func _get(prop_name: StringName):
	match prop_name:
		"/enemy_type_quantity":
			return enemy_type_quantity
		"enemy_type1":
			return enemy_type1
		"enemy_type2":
			return enemy_type2
		"enemy_type3":
			return enemy_type3
		"enemy_type4":
			return enemy_type4
		"enemy_type5":
			return enemy_type5
	
	return null