Godot Version
4.4.1
Question
I am making a tool script and in it I need to be able to get nodes that have a custom GD script on it. The custom script is ActionNode and nodes I want to find will extend this.
So normally the code would be this
static func filter(node: Node) -> void:
for child: Node in node.get_children():
print( child is ActionNode )
Here is a simplified version of my tool script for testing the problem
@tool
extends Node
@export var refresh: bool:
set(value):
refresh = value
_refresh()
@export var node: Node
func _refresh() -> void:
if not Engine.is_editor_hint():
return
print("action tool refresh")
extract(node)
static func extract(node: Node) -> void:
for child: Node in node.get_children():
if child.get_script():
print( child is ActionNode )
I have tried many things to be able to get the child nodes that are ActionNodes but since Tool scripts run in editor its a lot harder to get the type of a node, especially since I need to find subclasses (scripts that extend ActionNode).
Some things I have tried:
child is ActionNode = always false
# All ActionNodes have a var ACTION_ID
# child.get_script().get_path() will return the correct path
"ACTION_ID" in child = always false unless ActionNode and subclasses are @tool
"ACTION_ID" in load(child.get_script().get_path()) = always false
"ACTION_ID" in load(child.get_script().get_path()).new() = error (Nonexistent function 'new' in base 'GDScript'.)
var test_node: Node = Node.new()
test_node.set_script(load(child.get_script().get_path()))
test_node is ActionNode = always false unless ActionNode and subclasses are @tool
"ACTION_ID" in test_node = always false unless ActionNode and subclasses are @tool
# I was also told of a way to get the path to all custom classes
# this gets the path to ActionNode
var test: Dictionary = ProjectSettings.get_global_class_list().get( ProjectSettings.get_global_class_list().find_custom(func(dict: Dictionary): return dict["class"] == &"ActionNode") )
is_instance_of(test_node, load(test["path"])) = false unless ActionNode (not subclass), or if subclasses are @tool
"ACTION_ID" in load(test["path"]) = false
"ACTION_ID" in load(test["path"]).new() = true
# extra: I found that
# load(test["path"]) returns type Node
# load(child.get_script().get_path()) returns type GDScript
While writing this I found that this behaves differently based on how nodes are added to the tree. Above I added nodes as a Node (white circle icon) then dragged the scripts onto them to add the script. I then tried adding the nodes from the “Create New Node” menu but selecting the ActionNode subclasses. This results in the script icon for the node being greyed out and not changeable, but also results in
child is ActionNode = true
"ACTION_ID" in child = false unless @tool
"ACTION_ID" in test_node = false unless @tool
Is there a way to support the drag and drop method of adding a script to a node, without making all my classes tools? Or will this only work using the menu to select the node class I want?