Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change find_node to find_nodes and Add an type parameter. #56032

Merged
merged 1 commit into from
Feb 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions doc/classes/Node.xml
Original file line number Diff line number Diff line change
Expand Up @@ -181,16 +181,19 @@
[b]Note:[/b] It will not work properly if the node contains a script with constructor arguments (i.e. needs to supply arguments to [method Object._init] method). In that case, the node will be duplicated without a script.
</description>
</method>
<method name="find_node" qualifiers="const">
<return type="Node" />
<method name="find_nodes" qualifiers="const">
<return type="Node[]" />
<argument index="0" name="mask" type="String" />
<argument index="1" name="recursive" type="bool" default="true" />
<argument index="2" name="owned" type="bool" default="true" />
<argument index="1" name="type" type="String" default="&quot;&quot;" />
<argument index="2" name="recursive" type="bool" default="true" />
<argument index="3" name="owned" type="bool" default="true" />
<description>
Finds a descendant of this node whose name matches [code]mask[/code] as in [method String.match] (i.e. case-sensitive, but [code]"*"[/code] matches zero or more characters and [code]"?"[/code] matches any single character except [code]"."[/code]). Returns [code]null[/code] if no matching [Node] is found.
[b]Note:[/b] It does not match against the full path, just against individual node names.
Finds descendants of this node whose, name matches [code]mask[/code] as in [method String.match], and/or type matches [code]type[/code] as in [method Object.is_class].
[code]mask[/code] does not match against the full path, just against individual node names. It is case-sensitive, with [code]"*"[/code] matching zero or more characters and [code]"?"[/code] matching any single character except [code]"."[/code]).
[code]type[/code] will check equality or inheritance. It is case-sensitive, [code]"Object"[/code] will match a node whose type is [code]"Node"[/code] but not the other way around.
If [code]owned[/code] is [code]true[/code], this method only finds nodes whose owner is this node. This is especially important for scenes instantiated through a script, because those scenes don't have an owner.
[b]Note:[/b] As this method walks through all the descendants of the node, it is the slowest way to get a reference to another node. Whenever possible, consider using [method get_node] instead. To avoid using [method find_node] too often, consider caching the node reference into a variable.
Returns an empty array, if no matching nodes are found.
[b]Note:[/b] As this method walks through all the descendants of the node, it is the slowest way to get references to other nodes. To avoid using [method find_nodes] too often, consider caching the node references into variables.
</description>
</method>
<method name="find_parent" qualifiers="const">
Expand Down
5 changes: 3 additions & 2 deletions editor/import/scene_import_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -377,9 +377,10 @@ void SceneImportSettings::_update_view_gizmos() {
continue;
}

MeshInstance3D *collider_view = static_cast<MeshInstance3D *>(mesh_node->find_node("collider_view"));
CRASH_COND_MSG(collider_view == nullptr, "This is unreachable, since the collider view is always created even when the collision is not used! If this is triggered there is a bug on the function `_fill_scene`.");
TypedArray<Node> descendants = mesh_node->find_nodes("collider_view", "MeshInstance3D");
CRASH_COND_MSG(descendants.is_empty(), "This is unreachable, since the collider view is always created even when the collision is not used! If this is triggered there is a bug on the function `_fill_scene`.");

MeshInstance3D *collider_view = static_cast<MeshInstance3D *>(descendants[0].operator Object *());
collider_view->set_visible(generate_collider);
if (generate_collider) {
// This collider_view doesn't have a mesh so we need to generate a new one.
Expand Down
38 changes: 28 additions & 10 deletions scene/main/node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1344,27 +1344,45 @@ bool Node::has_node(const NodePath &p_path) const {
return get_node_or_null(p_path) != nullptr;
}

Node *Node::find_node(const String &p_mask, bool p_recursive, bool p_owned) const {
TypedArray<Node> Node::find_nodes(const String &p_mask, const String &p_type, bool p_recursive, bool p_owned) const {
TypedArray<Node> ret;
ERR_FAIL_COND_V(p_mask.is_empty() && p_type.is_empty(), ret);

Node *const *cptr = data.children.ptr();
int ccount = data.children.size();
for (int i = 0; i < ccount; i++) {
if (p_owned && !cptr[i]->data.owner) {
continue;
}
if (cptr[i]->data.name.operator String().match(p_mask)) {
return cptr[i];

if (!p_mask.is_empty()) {
if (!cptr[i]->data.name.operator String().match(p_mask)) {
continue;
} else if (p_type.is_empty()) {
ret.append(cptr[i]);
}
}

if (!p_recursive) {
continue;
if (cptr[i]->is_class(p_type)) {
ret.append(cptr[i]);
} else if (cptr[i]->get_script_instance()) {
Ref<Script> script = cptr[i]->get_script_instance()->get_script();
while (script.is_valid()) {
if ((ScriptServer::is_global_class(p_type) && ScriptServer::get_global_class_path(p_type) == script->get_path()) || p_type == script->get_path()) {
ret.append(cptr[i]);
break;
}

script = script->get_base_script();
}
}

Node *ret = cptr[i]->find_node(p_mask, true, p_owned);
if (ret) {
return ret;
if (p_recursive) {
ret.append_array(cptr[i]->find_nodes(p_mask, p_type, true, p_owned));
}
}
return nullptr;

return ret;
}

Node *Node::get_parent() const {
Expand Down Expand Up @@ -2706,7 +2724,7 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_node", "path"), &Node::get_node);
ClassDB::bind_method(D_METHOD("get_node_or_null", "path"), &Node::get_node_or_null);
ClassDB::bind_method(D_METHOD("get_parent"), &Node::get_parent);
ClassDB::bind_method(D_METHOD("find_node", "mask", "recursive", "owned"), &Node::find_node, DEFVAL(true), DEFVAL(true));
ClassDB::bind_method(D_METHOD("find_nodes", "mask", "type", "recursive", "owned"), &Node::find_nodes, DEFVAL(""), DEFVAL(true), DEFVAL(true));
ClassDB::bind_method(D_METHOD("find_parent", "mask"), &Node::find_parent);
ClassDB::bind_method(D_METHOD("has_node_and_resource", "path"), &Node::has_node_and_resource);
ClassDB::bind_method(D_METHOD("get_node_and_resource", "path"), &Node::_get_node_and_resource);
Expand Down
2 changes: 1 addition & 1 deletion scene/main/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ class Node : public Object {
bool has_node(const NodePath &p_path) const;
Node *get_node(const NodePath &p_path) const;
Node *get_node_or_null(const NodePath &p_path) const;
Node *find_node(const String &p_mask, bool p_recursive = true, bool p_owned = true) const;
TypedArray<Node> find_nodes(const String &p_mask, const String &p_type = "", bool p_recursive = true, bool p_owned = true) const;
bool has_node_and_resource(const NodePath &p_path) const;
Node *get_node_and_resource(const NodePath &p_path, RES &r_res, Vector<StringName> &r_leftover_subpath, bool p_last_is_property = true) const;

Expand Down