How to iterate the members of a class?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Zylann
:warning: Old Version Published before Godot 3 was released.

I have a GDScript class/script, for example this one:

class LevelAchievements:
var best_time = -1.0
var collected_orbs = 0
var death_count = -1
var completed_count = 0

var data = LevelAchievements.new()

In order to write it inside a savegame file, I want to iterate over its members rather than copy/paste everyting on save and load. Usually, this can be done through a form of reflection, but how is it possible to do that in GDScript?

Even better, is there a whay to query which members have export, and if so what is their type etc?

Not that I know of. There’s get_method_list() for functions but that’s all I can see. I use pretty much the save game method described in the manual.

duke_meister | 2016-06-10 00:57

I see there is get_property_list(), accordint to the doc it should return this:

Return the list of properties as an array of dictionaries, dictionaries contain: name:String, type:int (see TYPE_* enum in globals) and optionally: hint:int (see PROPERTY_HINT_* in globals), hint_string:String, usage:int (see PROPERTY_USAGE_* in globals).

So I tried:

class Foo:
	var one = 1
	var two = "two"
	var three

func _ready():
	var obj = Foo.new()
	var list = obj.get_property_list()
	for d in list:
		print("> " + d["name"])

But the result is completely off Oo

> Reference

I tried this instead:

var list = Foo.get_property_list()
for d in list:
	print("> " + d["name"])

More weirdness :o

> Reference
> Resource
> resource/path
> resource/name
> Script
> GDScript
> script/source

Either its a bug, or the function is badly named…

Zylann | 2016-06-10 13:00

Yeah i tried that too. I don’t think it’s properties as we know it.

duke_meister | 2016-06-10 15:05

A workaround would be to use var data = inst2dict(obj) and var obj = dict2inst(data), but it gets all properties, including @path and @subpath to indentify the class.

Zylann | 2016-06-11 14:24

:bust_in_silhouette: Reply From: davidoc

Your list is a dictionary array, iterate it this way:

var properties = node.get_property_list()

for i in range(properties.size()):
	print(properties[i].name + ", type: " + str(properties[i].type))

and to obtain the value by name use get:

var value = node.get("property_name")

It doesn’t works on classes:

class Test:
    var one = 1
    var two = "hahah"
    var three = []

Only prints:

Reference, type: 0

Adding export to the vars doesn’t change anything.

Zylann | 2016-10-14 23:14

Definitly a bug, it works with nodes, as a workaround you can extend your classes from Node until it’s fixed:

class Test extends Node:

davidoc | 2016-10-15 18:53

Even that won’t work for my use case, unfortunately…

Zylann | 2016-10-15 20:20

In Godot 3.2 stable the answer given by davidoc works correctly.

The following code

class LevelAchievements:
	var best_time = -1.0
	var collected_orbs = 0
	var death_count = -1
	var completed_count = 0
	
	func saveTest(file : String) -> void:
		pass
func _ready():	
	var data = LevelAchievements.new()
	data.best_time = 55.5
	data.collected_orbs = 100
	data.death_count = 20
	data.completed_count = 22
	var properties = data.get_property_list()
	for i in range(properties.size()):
		print(properties[i].name + ", type: " + str(properties[i].type) + " = " + str(data.get(properties[i].name)))
	var properties2 = data.get_method_list()
	print(properties2)

Gives the following output
Reference, type: 0 = Null
Script, type: 0 = Null
script, type: 17 = [GDScript:1184]
Script Variables, type: 0 = Null
best_time, type: 0 = 55.5
collected_orbs, type: 0 = 100
death_count, type: 0 = 20
completed_count, type: 0 = 22
…Methods information with method name, input arguments, return type etc.

rskgames | 2020-03-14 07:52