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

Add Node.get_unique_node() #64023

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

Mickeon
Copy link
Contributor

@Mickeon Mickeon commented Aug 7, 2022

Closes godotengine/godot-proposals#5048

This PR adds a new method to Node called get_unique_node(). The code is almost copied and pasted from part of get_node(). However, unlike the latter that passes through a NodePath, this method requires a StringName name as argument, and accesses the owned_unique_nodes directly.

This method is complete with autocompletion:

image

Also updates description of find_child() to mention get_unique_node().

As a comparison, this method is much slower when the appropriate parameters are passed (NotePath VS. StringName), but it is faster when normal String parameters are passed to both, which is what most common users would write.

The reason for this massive discrepancy can be attributed to the computing time it takes to append "%":

const StringName key = StringName(UNIQUE_NODE_PREFIX + p_name);

This is a requirement because, FOR SOME REASON, the "%" is included in the key when the Node is set as an unique name. I find it very unnecessary, as there's no way anything without "%" can be inserted into the owned_unique_nodes HashMap anyhow, but okay. I am emphasising this, because such a simple thing was the burden of me for 8+ hours.

This can probably be backported or cherrypicked to 3.x with no issues.

if (!unique) {
return nullptr;
}
return unique
Copy link
Contributor

@Spartan322 Spartan322 Aug 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is lacking a semicolon and a dereference.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I apologise for my ignorance, I'll update this PR soon, but what is a dereference in this case?

Copy link
Contributor

@Spartan322 Spartan322 Aug 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return *unique; You need to dereference unique because its currently becoming a pointer to a pointer of a Node and is not a pointer to a Node itself, you need to get the pointer to the Node, thus you dereference the pointer by doing *unique, (converting it from Node** to Node*) which is what get_node_or_null does.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, very gentle and insightful!

if (!unique) {
return nullptr;
}
return unique
Copy link
Contributor

@Spartan322 Spartan322 Aug 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is lacking a semicolon and a dereference.

@AaronRecord
Copy link
Contributor

Currently a draft because I don't know if this even works. I am, at least currently, unable to compile a version of Godot to test this out. If someone were to test for themselves, I'd appreciate that very much.

It's less convenient but FYI you can get compiler errors and download builds from the CI checks

@Mickeon
Copy link
Contributor Author

Mickeon commented Aug 7, 2022

Thank you! I "fixed" it and actually attempted to compile Godot, but this results into scene\main\node.cpp(1374): error C2440: 'initializing': cannot convert from 'const TValue *' to 'Node **. (Where // Has unique nodes in ownership is present).
Removing that part of the code makes it compile just fine, but now I'm just confused.


if (data.owned_unique_nodes.size()) {
// Has unique nodes in ownership
Node **unique = data.owned_unique_nodes.getptr(p_name);
Copy link
Contributor

@Spartan322 Spartan322 Aug 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

data.owned_unique_nodes.getptr(p_name) here actually references the const function making it return a Node *const * instead of Node **, this needs to be fixed with Node *const *unique = data.owned_unique_nodes.getptr(p_name); instead. (I forgot to check this specifically, sorry bout that)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's ok, how gentle! I figured just at the same time as this reply. It all compiles now.

@Mickeon Mickeon marked this pull request as ready for review August 7, 2022 19:33
@Mickeon Mickeon requested review from a team as code owners August 7, 2022 19:33
@Mickeon

This comment was marked as outdated.

@Mickeon Mickeon marked this pull request as draft August 7, 2022 21:03
@Mickeon Mickeon marked this pull request as ready for review August 8, 2022 08:49
@Mickeon
Copy link
Contributor Author

Mickeon commented Aug 8, 2022

Will implement autocompletion as well, soon.
I was trying to make it a static function for cleaner code, but it looks like the Node data and therefore owned_unique_nodes can't be accessed that way.

@Mickeon
Copy link
Contributor Author

Mickeon commented Aug 8, 2022

Explaining the concept in the docs is a bit untidy (scene /= owner). I may give a better shot at it another time. This is good for now.

@Mickeon
Copy link
Contributor Author

Mickeon commented Aug 8, 2022

Honestly afraid to push after rebase because it may unintentionally commit past, already committed PRs. Probably nothing to worry about...
image

@Spartan322
Copy link
Contributor

Spartan322 commented Aug 8, 2022

I feel like the unique node symbol being stored in the HashMap should be noted in an issue, personally I would think of it as a bug (even if its otherwise fairly insignificant except in this specific case) since there is no reason to store that, should leave it to functions to handle that manually.

@Mickeon
Copy link
Contributor Author

Mickeon commented Aug 8, 2022

I feel like the unique node symbol being stored in the HashMap should be noted in an issue

The code looks reasonably self-contained. I may just open another PR at a later point in time. It can't quite be reported as an issue and tested, because to the external eye, and the editor, it doesn't matter (owned_unique_nodes is not exposed)

It's possible this was done to speed up access using get_node("%Node"), as there would be no need to strip the prefix before using the name as a key.

@Spartan322
Copy link
Contributor

Spartan322 commented Aug 8, 2022

It can't quite be reported as an issue and tested, because to the external eye, and the editor, it doesn't matter (owned_unique_nodes is not exposed)

I guess, if it was immediately solved in a PR then bothering to put down the issue would be worthless, so long as an addressing PR isn't delayed, cause otherwise this problem would most certainly be forgotten.

It's possible this was done to speed up access using get_node("%Node"), as there would be no need to strip the prefix before using the name as a key.

Yeah, but since this PR overrides that specific case by being specific, maybe it should be addressed in this PR, I don't know.

@kleonc
Copy link
Member

kleonc commented Aug 8, 2022

Honestly afraid to push after rebase because it may unintentionally commit past, already committed PRs. Probably nothing to worry about...

@Mickeon Your branch is currently 55 commits behind the godot/master, it probably has the state of the godot/master at the time when you've created your branch (+it has your commits). Now you've pulled the changes from the current state of the godot/master (and transformed your commits into one). Pushing will make it be up to date with the current godot/master and will have your one additional commit. Looks good to force push to me.

@Mickeon
Copy link
Contributor Author

Mickeon commented Aug 8, 2022

Thank you all for the support! This was my first (actual) code contribution. It seems all good now.

@Mickeon Mickeon force-pushed the get-unique-node branch 2 times, most recently from a00b2f4 to 742dfd1 Compare August 9, 2022 09:39
@Mickeon
Copy link
Contributor Author

Mickeon commented Aug 9, 2022

Updated to use <param> and [param] instead of <argument> and [code] in Documentation

@Mickeon Mickeon force-pushed the get-unique-node branch 2 times, most recently from 63ce1ec to 742dfd1 Compare August 9, 2022 12:32
Also updates description of find_child() and find_parent() to mention get_unique_node()
ERR_FAIL_V_MSG(nullptr, "'name' parameter cannot be empty");
}

const StringName key = StringName(UNIQUE_NODE_PREFIX + p_name);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem with this approach is that this bit is actually quite inefficient compared to just requesting "%Node", so if we added this function and some users prefer it, it would be slower.

I am not sure how it can be done better, as it is not intended to be obtained like this.

Copy link
Contributor Author

@Mickeon Mickeon Aug 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is true, yeah. In fact, please see the benchmark in #64274

@adamscott
Copy link
Member

The GDScript team talked about this proposal during a meeting (that is somewhat related to the following godotengine/godot-proposals#5064).

We think that it would be a good idea to implement this kind of function for Node, especially if it gave some performance improvements.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add Node.get_unique_node() as a way to get Scene Unique Nodes
8 participants