+2 votes

I want to be able to detect if a given node has a given script type attached.

Suppose I have a 2D Sprite node named "mySprite" with a script file named "MySprite.gd"

In the parent of mySprite's script I do

const MySprite = preload("/path/to/MySprite.gd")

var spr = get_node("mySprite")
print( spr extends MySprite )

I thought this would be True but this results in False.

If I try printing spr:

print( str(spr) )

This results in [Sprite:588] instead of [MySprite:...]

EDIT:

I found out about get_script() however, I still can't make it work:

print(spr.get_script() == MySprite)
print(spr.get_script() extends MySprite)
print(spr.get_script().instance_has(MySprite) )
print(MySprite.instance_has(spr))
print(MySprite.instance_has(spr.get_script()))

All of the above print "False"

However if I do:

print(MySprite.get_source_code())
print(spr.get_script().get_source_code())

The output source code is identical.

EDIT:

I found out the problem. I tried doing

print(MySprite.get_path())
print(spr.get_script().get_path())

Turns out the result is:

res:///path/to/MySprite.gd
res://path/to/MySprite.gd

The paths are different when using absolute paths and relative paths! (The mySprite node uses a relative path). This causes the script object instances to be different. If I change it to both use relative paths then the script object becomes the same instance. I believe this is a bug which could be causing unnecessary loading of resources multiple times.

Note: bug filed here:
https://github.com/godotengine/godot/issues/4280

in Engine by (259 points)
edited by

2 Answers

+2 votes
Best answer

For comparisons I would use extends keyword instead, in that case you don't even need to use get_script() at all, just:

const MySpriteClass = preload("res://path/to/MySprite.gd")
var sprNode = get_node("mySprite")

(...)

var nodeExtendingSpriteClass = sprNode extends MySpriteClass; #true/false
print("spr node is an instance of MySpriteClass: ", str(nodeExtendingSpriteClass))

If you really need to get exactly "Class" of a scipt then I don't know if there is any direct method to do this... But you still can get path to the script file with:
var scriptFilePath = node.get_script().get_path()

So if a name of a file is a name of a class then it would be:
var scriptName = node.get_script().get_path().get_file()

by (1,293 points)
selected by

Yes, actually I just figured that out while fixing my code and came to update my answer.
I had the right idea right at the beginning ... it was just due to the absolute path resolution bug.

If you think this answer is better you should choose it, this way any person that will come in the future will be able to benefit.

Sorry, I edited my answer already ... I'll choose yours anyway :)

Note: In Godot 3.0 and later, the extends keyword for the purposes of type comparisons has been replaced with is:

if get_node("MyNode") is KinematicBody2D:
    print("MyNode inherits from KinematicBody2D.")
+1 vote

(Answering my own question)

The correct answer is:

const MySprite = preload("res://path/to/MySprite.gd")

var spr = get_node("mySprite")
print( spr extends MySprite)

The above will print True. The important thing is to use "res://path/to/MySprite.gd" as using "/path/to/MySprite.gd" results in the path being resolved to "res:///path/to/MySprite.gd".

I don't know if it is a bug or not, but it seems best practice is to use "res://path/to/thing" style paths for everything in GDScript.

This is because it looks like others have also had problems with non res:// style paths:

https://github.com/godotengine/godot/issues/4026
https://github.com/godotengine/godot/issues/3106

by (259 points)
edited by

Also there are not so many problems with relative paths, I'm using them all the time. One of the issues you had linked is more related to the fact that relative paths in Godot should not be started with "/" character.

Yes, I guess relative paths most of the time should be ok (except for issue 4026 above). In any case that should be fixed eventually.

Note: In Godot 3.0 and later, the extends keyword for the purposes of type comparisons has been replaced with is:

if get_node("MyNode") is KinematicBody2D:
    print("MyNode inherits from KinematicBody2D.")
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.