-
-
Notifications
You must be signed in to change notification settings - Fork 22.9k
Unique Node IDs (take 2) #106837
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?
Unique Node IDs (take 2) #106837
Conversation
5b243bd
to
8926a0b
Compare
Much better approach in my opinion. It's good that this is not exposed to the public API. |
Interesting that this PR uses Since this is intended to be useful for the 3D asset pipeline, is the intention to pitch to Khronos that unique node IDs use 32-bit integers in glTF? What about non-node unique IDs, like meshes having unique IDs? If we get a glTF unique ID extension, then that should apply to all items within a glTF file including nodes and resources. I would expect that Strings would be a more agnostic approach that would match resources and work the same across engines. |
What does that mean exactly? In what situation can a node disappear and get recovered? I don't see the IDs used anywhere other than Nodes' headers in the scene. |
When nodes in a inherited scene are renamed or moved, inheriting scenes are not aware of the change. As such, changes applied to inheriting scenes may be lost. This is a notorious issue as it discourages scene inheritance. You can also argue this is, in part, a consequence of no refactoring tools or automation on the editor side. |
Ah yeah, makes sense. I only tested whether nodes under editable children would disappear and it's still a problem, and it's btw what #73911 tries to solve. Not sure if it's planned? Another thing that IDs could fix, and they don't right now, are NodePath properties that become invalid when a node is moved externally. It's especially relevant for animations. |
Here's a MRP which can be used to reproduce the issue of losing local child nodes parented to an inherited scene's node (via Editable Children). This PR properly solves this issue (provided that the scenes have been saved at least once with this PR merged to save the unique node IDs). This scenario is described in a handful of issues I've seen in the past. I don't have time now to do a deep search, but it would be good if someone did to list which issues would be solved by this PR (or which ones could be but aren't). I found an edge case though, seen in this modified version of the MRP: In It's a bit of a corner case but I could see it happen occasionally due to the fact that our nodes have a default name, so it's easy enough to get name conflicts/reuse old names after rename. This seems to be due to this part of the design:
Why can't we use them as the first source of truth if they exist, instead of using them as fallback only? If they don't exist, we should fall back silently to using |
Well I tested and it doesn't work even for that 🤷♂️ godot.windows.editor.dev.x86_64_cA0ieFdKBQ.mp4Am I doing something wrong? Same with inherited scenes.
IIRC UIDs were also "fallback" in the beginning. |
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.
General question: Is it really safe to fall back to unique IDs when the parent instantiated scene changes? What if the structural changes imply a change to how the nodes should be stored?
Perhaps trying to restore is better than not trying, but it doesn't feel foolproof.
@@ -128,6 +128,10 @@ class Node : public Object { | |||
bool operator()(const Node *p_a, const Node *p_b) const { return p_b->is_greater_than(p_a); } | |||
}; | |||
|
|||
enum { | |||
UNIQUE_SCENE_ID_UNASSIGNED = 0 | |||
}; |
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 static constexpr uint32_t
could be used instead of an anonymous enum.
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.
Its my coding style and still pretty much everywhere around the project (including multiple places in this file). Not against new developers using something different 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.
Yea I guess it's mostly a style choice, but supplying an explicit type would be nice at least.
Also sorry for nitpicking so early, feel free to address this only when the PR has progressed some more!
} else { \ | ||
ERR_FAIL_INDEX_V(p_id & FLAG_MASK, nc, nullptr); \ | ||
p_name = ret_nodes[p_id & FLAG_MASK]; \ | ||
#define NODE_FROM_ID(p_name, p_id) \ |
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 this could be a function instead of a macro.
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.
Maybe, but it was like this before and this code is quite critical (any bug here can corrupt a project), so I prefer not to change it to not risk introducing potential bugs. I already had to be extremely careful and work little by little when working on this PR to ensure everything is kept as is.
Some answers to comments above:
Its just actually just a lot easier to mess up if IDs were the primary source of truth. This is what I tried in my previous PR (#86960). If you have an inherited scene, user could have copied and have duplicated IDs (used in instances or whathever in the base scene). That would be near impossible to figure out or fix for the user if broken. Text format would become so cryptic that it would be unusable to fix manually. This is why, this approach relies on strings first, and if not found it will rely on IDs. So, if IDs are messed up, nothing really happens. It's not 100% foolproof, but I don't think its really possible to do so (or worth the effort). To put it in other words:
|
The main goal of this PR is to safeguard when a base or instantiated scene changes (nodes renamed, moved or readded), that the hierarchy is still maintained and the node can be found. What it does: * Implements unique node IDs. * These IDs act as a fallback to names when saving. * The IDs are **USED AS A FALLBACK**, so they are just an addition. It should not break any current existing scene. * If a scene renames or moves a node, inherited or instantiated scenes will no longer lose reference to it. Unlike the previous approach, this one is intended to be a fallback, only used if the node is not found. This makes it safer to implement and ensure that, at worst case, we fail to find the node, but nothing breaks.
#106837 (comment) is still not addressed. |
The main goal of this PR is to safeguard when a base or instantiated scene changes (nodes renamed, moved or readded), that the hierarchy is still maintained and the node can be found.
Supersedes #86960.
What it does:
Unlike the previous approach, this one is intended to be a fallback, only used if the node is not found. This makes it safer to implement and ensure that, at worst case, we fail to find the node, but nothing breaks.