If an @tool script running in the editor tries to call a method on a script that does not have the @tool annotation, it produces an error:
Attempt to call a method on a placeholder instance. Check if the script is in tool mode.
The only problem is that I cannot figure out how to check if a script is in tool mode:
The documentation says
Any GDScript without @tool used by the editor will act like an empty file!
which implies that checking for a method or property in such a script would always return false.
if o.has_method("get_global_rect"): # this should be false if the script on this object is "like an empty file"
return o.get_global_rect()
However, this is not the case. method and property checking works as normal, and type checking also works as normal so I can’t use if o is InstancePlaceholder for example. I can find no way to detect the error before it happens, and since GDScript doesn’t have error handling, there also seems to be no way to deal with it after it happens.
What’s you use case where you don’t know if the script you’re calling is a tool script? Perhaps there’s another solution we could help you come up with to solve the problem.
func get_global_rect(o: Node) -> Rect2:
if not o:
return Rect2(Vector2.ZERO, Vector2.ZERO)
if o is not Actor or not Engine.is_editor_hint():
if o.has_method("get_global_rect"):
return o.get_global_rect()
if o.has_method("get_rect"):
var r = o.get_rect()
r.position += o.global_position
return r
return Rect2(o.global_position, Vector2.ZERO)
Since errors are only caused by code I wrote myself which doesn’t have the @tool annotation, that limits the number of cases I have to check for by quite a lot.
Here Actor is my class, and by ignoring it in the editor context I avoid the scary red error messages. It’s less of a case of “It doesn’t produce errors” so much as “it hasn’t produced errors yet”, and I will probably have to continue adding exceptions as the project matures.
Not so bad, but it would be nice to be able to write the code that adequately encapsulates the problem of:
if not running_this_will_cause_scary_red_errors(code):
code.run()
func get_global_rect(o: Node) -> Rect2:
if not o:
return Rect2(Vector2.ZERO, Vector2.ZERO)
# This check should prevent any risk of calling non-tool code from a tool
if not Engine.is_editor_hint() or o.get_script().is_tool():
if o.has_method("get_global_rect"):
return o.get_global_rect()
if o.has_method("get_rect"):
var r = o.get_rect()
r.position += o.global_position
return r
return Rect2(o.global_position, Vector2.ZERO)