-
-
Notifications
You must be signed in to change notification settings - Fork 23.4k
Add a method to construct a NodePath from a StringName #72702
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
base: master
Are you sure you want to change the base?
Conversation
I just ran into a situation where code that worked fine in 3.x doesn't due to this. Can this get merged into one of the patch releases? |
536d2b5
to
8f31602
Compare
8f31602
to
1c44cf2
Compare
1c44cf2
to
79f230d
Compare
Perhaps we just need to add the godot/core/variant/variant.cpp Lines 558 to 563 in e74bf83
godot/core/variant/variant.cpp Lines 714 to 718 in e74bf83
godot/core/variant/variant.cpp Lines 722 to 726 in e74bf83
|
79f230d
to
25c5898
Compare
@dalexeev Good idea, pushed a change to add that, but we should also keep the method exposed for explicitness. |
See also: godot/core/variant/variant_construct.cpp Lines 79 to 82 in fd31dc7
godot/core/variant/variant_construct.cpp Lines 176 to 182 in fd31dc7
Perhaps it makes sense to add constructors only in GDScript, even if we can't add them in C++? |
269b481
to
3475d55
Compare
3475d55
to
21f28d8
Compare
21f28d8
to
0f23e61
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good to me.
From the perspective of the C# bindings, I wonder if it'd be better to provide a static method or constructor that takes the StringName and just creates the NodePath assuming it contains no slashes or colons.
This would be an "unsafe" way to create a NodePath from StringName but I wouldn't expose this in the C# bindings. It would be used internally to create the NodePath when we can guarantee that the StringName doesn't contain slashes or colons. This means the logic to check this would be done in C# directly which would allow us to use IndexOfAny
which is vectorized.
However, using IndexOfAny
would require us to convert the StringName to a C# string first and that means creating a NodePath would take 2 interop calls instead of 1. I haven't benchmarked any of this so I don't know what would be better. It's possible that vectorizing the check for slashes and colons wouldn't bring much improvement over using this PR's static method, and I guess it's also possible to vectorize the C++ code in the future.
So, having said all that, I think this PR is still an improvement over the current way to create NodePaths from StringNames. I wonder if other language bindings authors are also interested in this API and would use it to either expose a way to create NodePaths from StringNames or, if it already exists, to improve their current implementation.
cc @Bromeon
0f23e61
to
974c0ae
Compare
974c0ae
to
a8fbe09
Compare
a8fbe09
to
6690df6
Compare
6690df6
to
e1c9aea
Compare
core/string/node_path.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes me think it'd be interesting to see if we should add a findmc
to complement findmk
, and perhaps a contains_any
or similar, there's many places that look for "is any of these present" and it'd be a good feature, just to think about I might look at an implementation later
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't that require constructing a Vector<char32_t>
, so less efficient than as it is now?
But in general, that seems like a good idea.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For two arguments I'd tend to agree
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have Span
now, so it could be Span<char32_t>
based now :)
e1c9aea
to
d2c2b7b
Compare
d2c2b7b
to
55433db
Compare
55433db
to
1210349
Compare
1210349
to
e317196
Compare
e317196
to
c82bfb7
Compare
c82bfb7
to
f4276f1
Compare
f4276f1
to
bf0112f
Compare
bf0112f
to
648bbf7
Compare
648bbf7
to
56240cf
Compare
56240cf
to
87598fe
Compare
87598fe
to
5dd92f0
Compare
5dd92f0
to
47a26de
Compare
47a26de
to
9bb2d5e
Compare
9bb2d5e
to
44d703c
Compare
44d703c
to
5b4ecd7
Compare
<method name="from_string_name" qualifiers="static"> | ||
<return type="NodePath" /> | ||
<param index="0" name="string_name" type="StringName" /> | ||
<description> | ||
Constructs a NodePath from a [StringName]. This method will be faster than constructing from a String if the StringName does not contain any slashes or colons. | ||
</description> | ||
</method> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my opinion, it makes no sense to expose identical constructor and static method. We can't make constructor in core for technical reasons, but in bindings we can choose what we will expose. However, I wonder if we will get the same problem with constructor in godot-cpp?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the static method is clearer, safer, and ensures we have a consistent API between C++ and GDScript. If both is not desired, then I will remove the constructor that you suggested (the second commit in this PR - glad I kept it separate 😛). EDIT: Removed, I have it saved locally if we need it back though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It sounds like you want to optimize the case where the NodePath
argument contains no :
or /
. This sounds like a great idea, but I think it's better material for NodePath(const String &p_path)
. It would be nice for any String
to NodePath
conversion to benefit from this, not just StringName
!
I'm also not sure if it's appropriate to add an implicit (strict) conversion from StringName
to NodePath
. Explicit (non-strict) conversions seem fine to me though, given that Node
names may also be used as paths.
@Ivorforce What specifically do you have in mind? What change to the The The advantage of checking for this with |
No, you're right, it does make sense to have a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With my updated understanding this totally makes sense.
Just some comments that need to be addressed before we can move forwards.
core/string/node_path.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have Span
now, so it could be Span<char32_t>
based now :)
void simplify(); | ||
NodePath simplified() const; | ||
|
||
static NodePath from_string_name(const StringName &p_string_name); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do like factory methods more than constructors, but we currently don't do this in the codebase much.
Perhaps we should go over this idea quickly in a core meeting to run it through the rest of the core team.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't? I thought we do. The existing cases in the codebase (will be helpful information during the meeting):
ArgumentDoc::from_dict
Basis::from_euler
Basis::from_scale
Color::from_hsv
Color::from_ok_hsl
Color::from_ok_hsv
Color::from_rgba8
Color::from_rgbe9995
Color::from_string
ConstantDoc::from_dict
DocData::ClassDoc::from_dict
EnumDoc::from_dict
GLTFCamera::from_dictionary
GLTFCamera::from_node
GLTFLight::from_dictionary
GLTFLight::from_node
GLTFPhysicsBody::from_dictionary
GLTFPhysicsBody::from_node
GLTFPhysicsShape::from_dictionary
GLTFPhysicsShape::from_node
GLTFPhysicsShape::from_resource
GLTFSkin::from_dictionary
GodotPosition::from_lsp
MethodDoc::from_dict
MethodInfo::from_dict
PropertyDoc::from_dict
PropertyInfo::from_dict
PropertyTweener::from_current
Quaternion::from_euler
RID::from_uint64
ScriptClassInfoUpdate::from_file_info
ThemeItemDoc::from_dict
TutorialDoc::from_dict
Vector2::from_angle
Though, most of the GLTF ones came from me, so I'm biased. 😛
bind_method(NodePath, slice, sarray("begin", "end"), varray(INT_MAX)); | ||
bind_method(NodePath, get_as_property_path, sarray(), varray()); | ||
bind_method(NodePath, is_empty, sarray(), varray()); | ||
bind_static_method(NodePath, from_string_name, sarray("string_name"), varray()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure we need to expose this function. From GDScript anyway the performance benefits are probably not that important (unless you want to test this?).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The API available through GDScript is the same as what's available through GDExtension. Also, I don't see a reason to prevent GDScript from using this method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's often brought up that we want to keep the GDScript API surface small and simple.
GDExtension is a good point. Personally I'd love to be able to expose methods to just GDExtension (and not GDScript when it's not useful there), but this is currently impossible, I suppose.
995f842
to
84aa752
Compare
84aa752
to
250419d
Compare
250419d
to
0d3b01c
Compare
0d3b01c
to
b7d957a
Compare
This allows constructing a NodePath directly from a StringName, which skips the String parsing logic, if the given StringName does not contain a slash or colon and can be used as-is.
I considered a constructor, but this would break all uses in the C++ code that construct NodePath from
char *
literals, and we need to depend on two other constructors anyway, so this uses a static method instead.