How to get class name of native class

Is there a way to get the name of an arbitrary native class as string?

get_class() only returns “GDScriptNativeClass”, not the actual name.

func _ready() -> void:
    print_name(CollisionObject2D)  # Should print "CollisionObject2D"

func print_name(type: Variant) -> void:
    print(type.get_name())  # Something like that

Note:
I know how type hints and type checking work in Godot. I really just need to know how to get the class name from an arbitrary type.

2 Likes

so you wanted to get the “class_name” from a node?

Not quite.
I need the name of an arbitrary native type, e.g. CollisionShape2D, Sprite2D, …, not the class_name of a custom script.

wont the get_class() do the job already?

No, as I wrote in my top post, it doesn’t

i tried to create Sprite2D, CollisionShape2D
and just .get_class(), it returns the exact same Sprite2D, CollisionShape2D
i dont know what you really want here

What? I get “GDScriptNativeClass”.
I’m working with Godot 4.

you will want it to be like this
image

if just get_class(), then it will return the gdscript

It’s not possible. It’s not exposed to the scripting language godot/modules/gdscript/gdscript.cpp at 26b1fd0d842fa3c2f090ead47e8ea7cd2d6515e1 · godotengine/godot · GitHub

I’m not sure what you may want to do, but generally do something like this when making decisions.

If obj is SomeClass:

They key word is “is”, which is a short form for is_instance_of

2 Likes

No, see my example in top post.
I pass the type to a function and need to extract the name from it.

I just did some more testing why I get “GDScriptNativeClass”.

print((CollisionObject2D as Object).get_class())  # Prints GDScriptNativeClass
print(CollisionObject2D.get_class())  # Crashes because there is no such static method.

It’s a little weird to see a different result when casting down to Object, but it makes sense there is no get_class method on that type.

Guess I’m out of luck here.

That is unfortunate. Wished there was a workaround.

I just tested this and get_class works as intended, I think you may be confused about the object that is being passed to that print statement.

code:
image

output:
image

Also there is the global ClassDB

func database_print():
	for _class in ClassDB.get_class_list():
		print(_class)

output:
image

You are passing instances into the function, not just the type.
I am not working with instances but with types, i.e. print_name(CollisionObject2D).
Also the list of class names does not help me here.

I don’t understand why though? what is our objective? I don’t see a reason to print the type like that. If you type the class name verbatim like that why not just make it a string? or use the node name self.name or just the self.get_class()

If you intend to spawn a specific type then use the ClassDB

var obj := ClassDB.instantiate("CollisionObject2D")

I have a utility function find_nodes_by_type(node: Node, type: Variant) -> Array[Node].
It does what the names suggests: it recursively searches the given node’s children for nodes of the given type and returns an array with all respective nodes.

Now consider the following use case:

var nodes: Array[CollisionObject2D] = find_nodes_by_type(some_node, CollisionObject2D)

It works as expected in the sense that it correctly retrieves all nodes with the given type.
However, it returns an Array[Node], not an Array[CollisionObject2D].
GDScript does not like this and will throw an error during runtime about trying to implicitly assign an Array[Node] to an Array[CollisionObject2D].

As a workaround you have to write:

var nodes: Array[CollisionObject2D] = []
nodes.assign(find_nodes_by_type(...))

This is a bit cumbersome, which is why I wanted to create a corresponding typed array in find_nodes_by_type using the typed array constructor so that further conversions are not necessary.
This constructor expects the type ID, the class name and optionally the script of the underlying type.
For script types, this is easy, but for native types I need the type name, which I can’t seem to get solely from the type parameter passed to the function.
And this brings us back to this question.

1 Like

Okay, that is a good use case, sorry for being a little dense.

Okay I get it now I thought I had seen a path through.

You may not like this, but I wonder if you could make a wrapper class that hosts the find function, and creates a dynamic script based on the type. Maybe throw some memorization so you don’t have to generate it dynamically every time? Although you will still have to define a return value.

Anyway I took a look at the source code and at the typed array function you mention, the script only has to be valid for the array type to work. That means it has be an instance. Although it’s not clear if it is used anywhere else.

Have you tried just casting with as instead of assigning?

Yes, I have tried as but it cannot be used for casting typed arrays.
See here: GDScript 2.0: Type casting (`as`) not working with typed arrays · Issue #54311 · godotengine/godot · GitHub.

Not sure how dynamically creating a script should help me there. I’m still lacking the native class name.

The typed array constructor needs the class name of the underlying native type and, if dealing with custom script types, a reference to the Script instance, not an instance of that script.

The underlying class name of a custom type can easily be retrieved using get_instance_base_type.
For native types it does not seem to be possible to retrieve the name without creating an instance first and then calling get_class() on that object.
Technically, it would be a workaround to create a temporary node instance for that purpose, but I’d rather use the Array.assign syntax.