-
-
Notifications
You must be signed in to change notification settings - Fork 21.3k
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
Fix resource_local_to_scene
in arrays and dictionaries
#87268
Conversation
Thanks for tackling this! ❤️
Redownloading the MRP fixed this. Unsure what's up with that... See later comment for more details. Also, you should likely remove the |
This comment was marked as outdated.
This comment was marked as outdated.
That's strange, as I thought it was working here. I have another test project where this fixed my issues, and the logs for the MRP seem right on my end.
|
resource_local_to_scene
in arrays.
Could you squash the commits? See PR workflow for instructions. |
ee13320
to
2b56e4b
Compare
Squashed and fixed formatting, hopefully good to go! |
I'm getting a deja vu here. Although that's probably all corner cases. The issue mentions also Dictionaries, so I think this PR could also handle them. It doesn't need to be recursive for now, but it would be nice if the copied code could be moved to some method. EDIT: void SceneState::setup_local_resource(Variant &r_value, HashMap<Ref<Resource>, Ref<Resource>> &p_resources_local_to_sub_scene, HashMap<Ref<Resource>, Ref<Resource>> &p_resources_local_to_scene, const SceneState::NodeData &p_node_data, Node *p_node, Node *p_base, const StringName &p_property, int p_edit_state) const {
Ref<Resource> resource = r_value;
if (resource.is_null() || !resource->is_local_to_scene()) {
return;
}
if (p_node_data.instance >= 0) { // For the root node of a sub-scene, treat it as part of the sub-scene.
r_value = get_remap_resource(resource, p_resources_local_to_sub_scene, p_node->get(p_property), p_node);
} else {
HashMap<Ref<Resource>, Ref<Resource>>::Iterator E = p_resources_local_to_scene.find(resource);
if (E) {
r_value = E->value;
} else {
if (p_edit_state == GEN_EDIT_STATE_MAIN) {
// For the main scene, use the resource as is.
resource->configure_for_local_scene(p_base, p_resources_local_to_scene);
p_resources_local_to_scene[resource] = resource;
} else {
// For instances, a copy must be made.
Ref<Resource> local_dupe = resource->duplicate_for_local_scene(p_base, p_resources_local_to_scene);
p_resources_local_to_scene[resource] = local_dupe;
r_value = local_dupe;
}
}
}
} It has ugly argument list, because there is many local variables involved. And also it doesn't work for some reason .-. btw I also made a simpler reproduction project: |
This zip is missing the script I think. I'll try to implement the method you outlined. As for dictionaries, I'm not certain how to tackle it, should I check for object and then dictionary? (pseudo code below)
And yeah, the nesting is certainly an issue, I'll see if I can deal with it too while I'm at it. |
You can get inspired by my PR that tackled the other half of the issue: #71578 So your pseudo code would need to switch over the variant types OBJECT, ARRAY, DICTIONARY and act accordingly. |
Sorry, here's a fixed one:
Dictionary is not Object. Also I wouldn't really bother for recursive checking, as it often caused performance problems. For now handling only top level properties is fine I think. |
The issue so far is that the resource is always duplicated now, even if it already was. What this does (to my understanding) is that the values get re-duplicated every time you open the scene. void SceneState::setup_local_resource(Ref<Resource>& r_res, Array& p_origin_array, const int p_origin_array_index, const SceneState::NodeData& p_node_data, HashMap<Ref<Resource>, Ref<Resource>>& p_resources_local_to_sub_scene, Node* p_node, const StringName p_sname, HashMap<Ref<Resource>, Ref<Resource>>& p_resources_local_to_scene, int p_i, Node** p_ret_nodes, SceneState::GenEditState p_edit_state) const
{
if (!r_res->is_local_to_scene()) {
printf("Resource was not local.\n");
return;
}
if (p_node_data.instance >= 0) { // For the root node of a sub-scene, treat it as part of the sub-scene.
p_origin_array[p_origin_array_index] = get_remap_resource(r_res, p_resources_local_to_sub_scene, p_node->get(p_sname), p_node);
printf("Remapping.\n");
} else {
HashMap<Ref<Resource>, Ref<Resource>>::Iterator E = p_resources_local_to_scene.find(r_res);
Node* base = p_i == 0 ? p_node : p_ret_nodes[0];
if (E) {
p_origin_array[p_origin_array_index] = E->value;
printf("Found original, no change.\n");
} else if (p_edit_state == GEN_EDIT_STATE_MAIN) {
// For the main scene, use the resource as is.
r_res->configure_for_local_scene(base, p_resources_local_to_scene);
p_resources_local_to_scene[r_res] = r_res;
printf("Main scene.\n");
} else {
// For instances, a copy must be made.
Ref<Resource> local_dupe = r_res->duplicate_for_local_scene(base, p_resources_local_to_scene);
p_resources_local_to_scene[r_res] = local_dupe;
p_origin_array[p_origin_array_index] = local_dupe;
printf("Duplicate for local scene.\n");
}
}
}
HashMap<Ref<Resource>, Ref<Resource>>::Iterator E = p_resources_local_to_scene.find(r_res); Your test scene works btw, when the nodes are modified at runtime they are properly duplicated, so that's good. |
I'm so close, but I can't put together the final line(s) needed. The reason @KoBeWi 's method doesn't work is because the final variant needs to be assigned to value, but we were just assigning it to the Ref previously. I made a version that returns a Ref and assigns it to value and it works now. I imagine it's the same thing with the array, but despite attempting to assign value to the modified array I still run into the same issues as above. I'm not sure if Arrays have a special way of being assigned though that I might be missing however. This is my version of your method now btw: Ref<Resource> SceneState::make_local_resource(Variant& r_value, const SceneState::NodeData& p_node_data, HashMap<Ref<Resource>, Ref<Resource>>& p_resources_local_to_sub_scene, Node* p_node, const StringName p_sname, HashMap<Ref<Resource>, Ref<Resource>>& p_resources_local_to_scene, int p_i, Node** p_ret_nodes, SceneState::GenEditState p_edit_state) const
{
Ref<Resource> res = r_value;
if (res.is_null() || !res->is_local_to_scene()) {
return r_value;
}
if (p_node_data.instance >= 0) { // For the root node of a sub-scene, treat it as part of the sub-scene.
return get_remap_resource(res, p_resources_local_to_sub_scene, p_node->get(p_sname), p_node);
} else {
HashMap<Ref<Resource>, Ref<Resource>>::Iterator E = p_resources_local_to_scene.find(res);
Node* base = p_i == 0 ? p_node : p_ret_nodes[0];
if (E) {
return E->value;
} else if (p_edit_state == GEN_EDIT_STATE_MAIN) { // For the main scene, use the resource as is
res->configure_for_local_scene(base, p_resources_local_to_scene);
p_resources_local_to_scene[res] = res;
return res;
} else { // For instances, a copy must be made.
Ref<Resource> local_dupe = res->duplicate_for_local_scene(base, p_resources_local_to_scene);
p_resources_local_to_scene[res] = local_dupe;
return local_dupe;
}
}
} EDIT: the scene does not save the resource locally, maybe the issue is somewhere else? |
Getting more specific: the issue seems to be that the default value for the array is not properly referencing the value from the parent scene: // packed_scene.cpp
if (!pinned_props.has(name)) {
bool is_valid_default = false;
// FIXME: the default_value is the current value rather than the value in the parent scene
Variant default_value = PropertyUtils::get_property_default_value(p_node, name, &is_valid_default, &states_stack, true);
if (is_valid_default && !PropertyUtils::is_property_value_different(value, default_value)) {
continue;
}
} I believe the error is in the PropertyUtils::get_node_states_stack method, but this is getting way over my head unfortunately. |
Is this intended to be a work in progress currently? If so you might want to convert it to a draft 🙂 |
2227451
to
b5b1327
Compare
9d0af5d
to
83ef03a
Compare
Looks better now, but something is wrong with Dictionaries. When you have both key and value local to scene, they double when loading the scene Also you should remove the commented out code. |
a2868e7
to
e13093a
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.
Works correctly now. You still need to remove the commented out code as I mentioned.
…ow properly work inside arrays and dictionaries.
Thanks! And congrats for your first merged Godot contribution 🎉 |
resource_local_to_scene
in arrays.resource_local_to_scene
in arrays and dictionaries
resource_local_to_scene
in arrays and dictionariesresource_local_to_scene
in arrays and dictionaries
Attempts to fix resource_local_to_scene in arrays, see #71243.
Bugsquad edit: