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 a get_partial_path method to NodePath #7148

Closed
aaronfranke opened this issue Jun 24, 2023 · 14 comments · Fixed by godotengine/godot#81822
Closed

Add a get_partial_path method to NodePath #7148

aaronfranke opened this issue Jun 24, 2023 · 14 comments · Fixed by godotengine/godot#81822
Milestone

Comments

@aaronfranke
Copy link
Member

aaronfranke commented Jun 24, 2023

Describe the project you are working on

A game with a lot of dynamic code.

Describe the problem or limitation you are having in your project

Currently, if you have a NodePath like ^"A/B/C/D/E/F", there is no easy way to get only the first X names in the path, such as if you only wanted the first 4 names ^"A/B/C/D".

The only way to get this would be to manually reconstruct it in GDScript. However, this would be extremely inefficient compared to what's optimal, since the NodePath constructor that accepts an array of StringNames is not exposed, it's only internal to the engine, so you would have to build a String which then gets split up again. Horrible!

Describe the feature / enhancement and how it helps to overcome the problem or limitation

Add a method that allows getting a partial path from a NodePath.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

See this PR: godotengine/godot#78638

If this enhancement will not be used often, can it be worked around with a few lines of script?

It can be worked around but not in a few lines and extremely inefficiently.

I don't know how often this will be used. I suspect that this will not be used often, but I have no idea.

Is there a reason why this should be core and not an add-on in the asset library?

Yes, because this is heavily related to NodePath and NodePath is a part of core. The ability to manipulate NodePaths to get other NodePaths seems like a very core feature that NodePath should have.

@YuriSizov
Copy link
Contributor

This does sound very specific to your particular project. What would be a common use case for that? You explain what you need specifically, but not what the context of it is.

@Zireael07
Copy link

Zireael07 commented Jun 26, 2023

Literally what they said, a project with dynamic paths. I have two procgen projects and both of them suffer from this issue of me having to retype parts of nodepaths, which can get quite long. This is a PITA to maintain... and Aaron is right it's also a perf issue

(Unique nodes don't work outside of their base scene, so won't help in 90% of cases, they would only help for GUI menus and only some at that - because some of my menus are also dynamic)

@YuriSizov
Copy link
Contributor

@Zireael07 I don't understand how you want to use these partials to help your code. Can you, or Aaron, give an example of a problem and how this change would solve it?

@Zireael07
Copy link

Zireael07 commented Jun 26, 2023

I have a complex skeleton for a FPS game. It's imported, and I can't move things around because otherwise things break, so to get any of bones/bone attachments I have to do this: $mesh/armature/skeleton/bone1, or $mesh/armature/skeleton/attachment2, and sometimes attachments have nested children too, so to get a sniper scope on my rifle I do $mesh/armature/skeleton/handattachment2/rifle/scope... you get the idea. This is, I think, the most egregious case (and I do a LOT of those for IK and/or enabling/disabling features, or ragdolling)

Another example: $starmap/UI/controls/button1, $starmap/UI/controls/button2 etc. repeated 4 times for panning controls, and then once again for another player control. Same, but much worse, problem for star icons (which are procedurally generated: $starmap/control/control/, and I can't unnest because otherwise transforms break)

This feature would allow me to break out and store somewhere the common, repeated parts (which are truncated for readability in this post, and in actuality can be much longer because e.g. attachment or rifle or button is not actually named that, it has a longer name)

@YuriSizov
Copy link
Contributor

YuriSizov commented Jun 26, 2023

This feature would allow me to break out and store somewhere the common, repeated parts (which are truncated for readability in this post, and in actuality can be much longer because e.g. attachment or rifle or button is not actually named that, it has a longer name)

What benefit this has over picking a node somewhere midway and using its get_path? E.g. if you want to have a prefix for all your skeleton bits, you'd get your $mesh/armature/skeleton and use that as a reference, either as a node reference or as a node path with get_path/get_relative_path?

From your description you clearly need to have some knowledge of the internal structure, so finding some common parent node shouldn't be a problem over finding the exact child and doing something like get_partial_path(3).

@Zireael07
Copy link

Using a node when all I need is a NodePath strikes me as overkill.

Aaron also seems to indicate some performance problems with that?

@YuriSizov
Copy link
Contributor

YuriSizov commented Jun 26, 2023

Using a node when all I need is a NodePath strikes me as overkill.

You still need a node to use this new method. And with what I'm describing you don't have to store a node reference if you don't want to, you can store a node path corresponding to that node.

@aaronfranke
Copy link
Member Author

@YuriSizov I am designing a system for building a tree out of (some) properties of nodes. So in that tree I have TreeItems representing nodes. But I build this tree starting with a list of properties, like {^"/root/A/B/C/D/E/F": property}, which I use to create the intermediate TreeItems and get their names with NodePath.get_name(index). I want to also allow operations on the intermediate parent nodes, so I need each of those TreeItems to keep track of the NodePath, but currently this is not possible to do in a performant way.

@nlupugla
Copy link

What not just expose the NodePath method that converts it into an array of strings? Then you can slice the array to get whatever part of the path you want. Better yet, introduce a NodePath slice function. That way it's independent of the underlying representation.

@nlupugla
Copy link

nlupugla commented Sep 16, 2023

I can write a quick PR for a NodePath::slice function if there's interest. It might even be fewer lines of code than this PR.

@aaronfranke
Copy link
Member Author

aaronfranke commented Sep 16, 2023

I like slice, it's a superset of this proposal's functionality so it will work for my use cases.

@nlupugla
Copy link

My plan for implementation is just to forward the slice parameters to a slice on the underlying String Vectors. I assume that if the calling NodePath is relative, the slice should also be considered relative yeah?

@nlupugla
Copy link

@aaronfranke Finished writing up my pr :) godotengine/godot#81822

Let me know if my implementation does what you need.

@aaronfranke
Copy link
Member Author

See also godotengine/godot#72702 for constructing a NodePath from a StringName.

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