mirror of
https://github.com/godotengine/godot.git
synced 2025-12-08 06:09:55 +00:00
Fix resource shared when duplicating an instanced scene
For resources with `resource_local_to_scene` enabled in the sub-scene, the resource is already set when the sub-scene is instantiated, so does not need to be set again. Just needs to update the property of the resource according to the value in the main scene.
This commit is contained in:
parent
1b4f116db1
commit
e0532a711a
5 changed files with 72 additions and 29 deletions
|
|
@ -907,6 +907,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HashMap<Node *, HashMap<Ref<Resource>, Ref<Resource>>> &resources_local_to_scenes = clipboard_resource_remap[edited_scene->get_scene_file_path()];
|
||||||
|
|
||||||
for (Node *node : selection) {
|
for (Node *node : selection) {
|
||||||
Node *parent = node->get_parent();
|
Node *parent = node->get_parent();
|
||||||
|
|
||||||
|
|
@ -922,7 +924,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
|
||||||
}
|
}
|
||||||
|
|
||||||
HashMap<const Node *, Node *> duplimap;
|
HashMap<const Node *, Node *> duplimap;
|
||||||
Node *dup = node->duplicate_from_editor(duplimap);
|
Node *dup = node->duplicate_from_editor(duplimap, edited_scene, resources_local_to_scenes);
|
||||||
|
|
||||||
ERR_CONTINUE(!dup);
|
ERR_CONTINUE(!dup);
|
||||||
|
|
||||||
|
|
@ -956,6 +958,14 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
|
||||||
|
|
||||||
undo_redo->commit_action();
|
undo_redo->commit_action();
|
||||||
|
|
||||||
|
for (KeyValue<Node *, HashMap<Ref<Resource>, Ref<Resource>>> &KV : resources_local_to_scenes) {
|
||||||
|
for (KeyValue<Ref<Resource>, Ref<Resource>> &R : KV.value) {
|
||||||
|
if (R.value->is_local_to_scene()) {
|
||||||
|
R.value->setup_local_to_scene();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (dupsingle) {
|
if (dupsingle) {
|
||||||
_push_item(dupsingle);
|
_push_item(dupsingle);
|
||||||
}
|
}
|
||||||
|
|
@ -4334,26 +4344,25 @@ List<Node *> SceneTreeDock::paste_nodes(bool p_paste_as_sibling) {
|
||||||
}
|
}
|
||||||
ur->add_do_method(editor_selection, "clear");
|
ur->add_do_method(editor_selection, "clear");
|
||||||
|
|
||||||
HashMap<Ref<Resource>, Ref<Resource>> resource_remap;
|
|
||||||
String target_scene;
|
String target_scene;
|
||||||
if (edited_scene) {
|
if (edited_scene) {
|
||||||
target_scene = edited_scene->get_scene_file_path();
|
target_scene = edited_scene->get_scene_file_path();
|
||||||
}
|
}
|
||||||
|
HashMap<Node *, HashMap<Ref<Resource>, Ref<Resource>>> &resources_local_to_scenes = clipboard_resource_remap[target_scene]; // Record the mappings in the sub-scene.
|
||||||
if (target_scene != clipboard_source_scene) {
|
if (target_scene != clipboard_source_scene) {
|
||||||
if (!clipboard_resource_remap.has(target_scene)) {
|
if (!resources_local_to_scenes.has(nullptr)) {
|
||||||
HashMap<Ref<Resource>, Ref<Resource>> remap;
|
HashMap<Ref<Resource>, Ref<Resource>> remap;
|
||||||
for (Node *E : node_clipboard) {
|
for (Node *E : node_clipboard) {
|
||||||
_create_remap_for_node(E, remap);
|
_create_remap_for_node(E, remap);
|
||||||
}
|
}
|
||||||
clipboard_resource_remap[target_scene] = remap;
|
resources_local_to_scenes[nullptr] = remap;
|
||||||
}
|
}
|
||||||
resource_remap = clipboard_resource_remap[target_scene];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Node *node : node_clipboard) {
|
for (Node *node : node_clipboard) {
|
||||||
HashMap<const Node *, Node *> duplimap;
|
HashMap<const Node *, Node *> duplimap;
|
||||||
|
|
||||||
Node *dup = node->duplicate_from_editor(duplimap, resource_remap);
|
Node *dup = node->duplicate_from_editor(duplimap, edited_scene, resources_local_to_scenes);
|
||||||
ERR_CONTINUE(!dup);
|
ERR_CONTINUE(!dup);
|
||||||
|
|
||||||
pasted_nodes.push_back(dup);
|
pasted_nodes.push_back(dup);
|
||||||
|
|
@ -4396,6 +4405,15 @@ List<Node *> SceneTreeDock::paste_nodes(bool p_paste_as_sibling) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ur->commit_action();
|
ur->commit_action();
|
||||||
|
|
||||||
|
for (KeyValue<Node *, HashMap<Ref<Resource>, Ref<Resource>>> &KV : resources_local_to_scenes) {
|
||||||
|
for (KeyValue<Ref<Resource>, Ref<Resource>> &R : KV.value) {
|
||||||
|
if (R.value->is_local_to_scene()) {
|
||||||
|
R.value->setup_local_to_scene();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return pasted_nodes;
|
return pasted_nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,7 @@ class SceneTreeDock : public EditorDock {
|
||||||
List<Node *> node_clipboard;
|
List<Node *> node_clipboard;
|
||||||
HashSet<Node *> node_clipboard_edited_scene_owned;
|
HashSet<Node *> node_clipboard_edited_scene_owned;
|
||||||
String clipboard_source_scene;
|
String clipboard_source_scene;
|
||||||
HashMap<String, HashMap<Ref<Resource>, Ref<Resource>>> clipboard_resource_remap;
|
HashMap<String, HashMap<Node *, HashMap<Ref<Resource>, Ref<Resource>>>> clipboard_resource_remap;
|
||||||
|
|
||||||
ScriptCreateDialog *script_create_dialog = nullptr;
|
ScriptCreateDialog *script_create_dialog = nullptr;
|
||||||
ShaderCreateDialog *shader_create_dialog = nullptr;
|
ShaderCreateDialog *shader_create_dialog = nullptr;
|
||||||
|
|
|
||||||
|
|
@ -2953,10 +2953,11 @@ Node *Node::duplicate(int p_flags) const {
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
Node *Node::duplicate_from_editor(HashMap<const Node *, Node *> &r_duplimap) const {
|
Node *Node::duplicate_from_editor(HashMap<const Node *, Node *> &r_duplimap) const {
|
||||||
return duplicate_from_editor(r_duplimap, HashMap<Ref<Resource>, Ref<Resource>>());
|
HashMap<Node *, HashMap<Ref<Resource>, Ref<Resource>>> tmp;
|
||||||
|
return duplicate_from_editor(r_duplimap, nullptr, tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
Node *Node::duplicate_from_editor(HashMap<const Node *, Node *> &r_duplimap, const HashMap<Ref<Resource>, Ref<Resource>> &p_resource_remap) const {
|
Node *Node::duplicate_from_editor(HashMap<const Node *, Node *> &r_duplimap, Node *p_scene_root, HashMap<Node *, HashMap<Ref<Resource>, Ref<Resource>>> &p_resource_remap) const {
|
||||||
int flags = DUPLICATE_SIGNALS | DUPLICATE_GROUPS | DUPLICATE_SCRIPTS | DUPLICATE_USE_INSTANTIATION | DUPLICATE_FROM_EDITOR;
|
int flags = DUPLICATE_SIGNALS | DUPLICATE_GROUPS | DUPLICATE_SCRIPTS | DUPLICATE_USE_INSTANTIATION | DUPLICATE_FROM_EDITOR;
|
||||||
Node *dupe = _duplicate(flags, &r_duplimap);
|
Node *dupe = _duplicate(flags, &r_duplimap);
|
||||||
|
|
||||||
|
|
@ -2969,8 +2970,8 @@ Node *Node::duplicate_from_editor(HashMap<const Node *, Node *> &r_duplimap, con
|
||||||
_duplicate_properties(this, this, dupe, flags);
|
_duplicate_properties(this, this, dupe, flags);
|
||||||
|
|
||||||
// This is used by SceneTreeDock's paste functionality. When pasting to foreign scene, resources are duplicated.
|
// This is used by SceneTreeDock's paste functionality. When pasting to foreign scene, resources are duplicated.
|
||||||
if (!p_resource_remap.is_empty()) {
|
if (p_scene_root) {
|
||||||
remap_node_resources(dupe, p_resource_remap);
|
remap_node_resources(dupe, p_scene_root, p_resource_remap);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Duplication of signals must happen after all the node descendants have been copied,
|
// Duplication of signals must happen after all the node descendants have been copied,
|
||||||
|
|
@ -2981,7 +2982,9 @@ Node *Node::duplicate_from_editor(HashMap<const Node *, Node *> &r_duplimap, con
|
||||||
return dupe;
|
return dupe;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::remap_node_resources(Node *p_node, const HashMap<Ref<Resource>, Ref<Resource>> &p_resource_remap) const {
|
void Node::remap_node_resources(Node *p_node, Node *p_scene_root, HashMap<Node *, HashMap<Ref<Resource>, Ref<Resource>>> &p_resource_remap) const {
|
||||||
|
Node *local_scene = p_node->is_instance() ? p_node : (p_node->get_owner() ? p_node->get_owner() : p_scene_root);
|
||||||
|
|
||||||
List<PropertyInfo> props;
|
List<PropertyInfo> props;
|
||||||
p_node->get_property_list(&props);
|
p_node->get_property_list(&props);
|
||||||
|
|
||||||
|
|
@ -2991,23 +2994,39 @@ void Node::remap_node_resources(Node *p_node, const HashMap<Ref<Resource>, Ref<R
|
||||||
}
|
}
|
||||||
|
|
||||||
Variant v = p_node->get(E.name);
|
Variant v = p_node->get(E.name);
|
||||||
if (v.is_ref_counted()) {
|
if (!v.is_ref_counted()) {
|
||||||
Ref<Resource> res = v;
|
continue;
|
||||||
if (res.is_valid()) {
|
}
|
||||||
if (p_resource_remap.has(res)) {
|
Ref<Resource> res = v;
|
||||||
p_node->set(E.name, p_resource_remap[res]);
|
if (res.is_null()) {
|
||||||
remap_nested_resources(res, p_resource_remap);
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (res->is_local_to_scene()) {
|
||||||
|
if (local_scene == res->get_local_scene()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Ref<Resource> dup = SceneState::get_remap_resource(res, p_resource_remap, nullptr, local_scene);
|
||||||
|
p_node->set(E.name, dup);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res->is_built_in()) {
|
||||||
|
// Use nullptr instead of a specific node (current scene root node) to represent the scene,
|
||||||
|
// as the Make Scene Root operation may be executed.
|
||||||
|
if (p_resource_remap[nullptr].has(res)) {
|
||||||
|
p_node->set(E.name, p_resource_remap[nullptr][res]);
|
||||||
|
remap_nested_resources(res, p_resource_remap[nullptr]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < p_node->get_child_count(); i++) {
|
for (int i = 0; i < p_node->get_child_count(); i++) {
|
||||||
remap_node_resources(p_node->get_child(i), p_resource_remap);
|
remap_node_resources(p_node->get_child(i), p_scene_root, p_resource_remap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::remap_nested_resources(Ref<Resource> p_resource, const HashMap<Ref<Resource>, Ref<Resource>> &p_resource_remap) const {
|
void Node::remap_nested_resources(Ref<Resource> p_resource, HashMap<Ref<Resource>, Ref<Resource>> &p_resource_remap) const {
|
||||||
List<PropertyInfo> props;
|
List<PropertyInfo> props;
|
||||||
p_resource->get_property_list(&props);
|
p_resource->get_property_list(&props);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -721,9 +721,9 @@ public:
|
||||||
Node *duplicate(int p_flags = DUPLICATE_GROUPS | DUPLICATE_SIGNALS | DUPLICATE_SCRIPTS) const;
|
Node *duplicate(int p_flags = DUPLICATE_GROUPS | DUPLICATE_SIGNALS | DUPLICATE_SCRIPTS) const;
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
Node *duplicate_from_editor(HashMap<const Node *, Node *> &r_duplimap) const;
|
Node *duplicate_from_editor(HashMap<const Node *, Node *> &r_duplimap) const;
|
||||||
Node *duplicate_from_editor(HashMap<const Node *, Node *> &r_duplimap, const HashMap<Ref<Resource>, Ref<Resource>> &p_resource_remap) const;
|
Node *duplicate_from_editor(HashMap<const Node *, Node *> &r_duplimap, Node *p_scene_root, HashMap<Node *, HashMap<Ref<Resource>, Ref<Resource>>> &p_resource_remap) const;
|
||||||
void remap_node_resources(Node *p_node, const HashMap<Ref<Resource>, Ref<Resource>> &p_resource_remap) const;
|
void remap_node_resources(Node *p_node, Node *p_scene_root, HashMap<Node *, HashMap<Ref<Resource>, Ref<Resource>>> &p_resource_remap) const;
|
||||||
void remap_nested_resources(Ref<Resource> p_resource, const HashMap<Ref<Resource>, Ref<Resource>> &p_resource_remap) const;
|
void remap_nested_resources(Ref<Resource> p_resource, HashMap<Ref<Resource>, Ref<Resource>> &p_resource_remap) const;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// used by editors, to save what has changed only
|
// used by editors, to save what has changed only
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,13 @@ static Array _sanitize_node_pinned_properties(Node *p_node) {
|
||||||
Ref<Resource> SceneState::get_remap_resource(const Ref<Resource> &p_resource, HashMap<Node *, HashMap<Ref<Resource>, Ref<Resource>>> &remap_cache, const Ref<Resource> &p_fallback, Node *p_for_scene) {
|
Ref<Resource> SceneState::get_remap_resource(const Ref<Resource> &p_resource, HashMap<Node *, HashMap<Ref<Resource>, Ref<Resource>>> &remap_cache, const Ref<Resource> &p_fallback, Node *p_for_scene) {
|
||||||
ERR_FAIL_COND_V(p_resource.is_null(), Ref<Resource>());
|
ERR_FAIL_COND_V(p_resource.is_null(), Ref<Resource>());
|
||||||
|
|
||||||
bool reuse_fallback = p_fallback.is_valid() && p_fallback->is_local_to_scene() && p_fallback->get_class() == p_resource->get_class();
|
// Find the shared copy of the source resource.
|
||||||
|
HashMap<Ref<Resource>, Ref<Resource>>::Iterator R = remap_cache[p_for_scene].find(p_resource);
|
||||||
|
if (R) {
|
||||||
|
return R->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool reuse_fallback = p_fallback.is_valid() && p_fallback->is_local_to_scene() && p_fallback->get_class_name() == p_resource->get_class_name();
|
||||||
|
|
||||||
if (reuse_fallback) {
|
if (reuse_fallback) {
|
||||||
// The fallback resource can only be mapped at most once when it is valid.
|
// The fallback resource can only be mapped at most once when it is valid.
|
||||||
|
|
@ -703,16 +709,16 @@ Variant SceneState::make_local_resource(Variant &p_value, const SceneState::Node
|
||||||
|
|
||||||
Node *base = (p_i == 0 || p_node->is_instance()) ? p_node : (p_node->get_owner() ? p_node->get_owner() : p_ret_nodes[0]);
|
Node *base = (p_i == 0 || p_node->is_instance()) ? p_node : (p_node->get_owner() ? p_node->get_owner() : p_ret_nodes[0]);
|
||||||
|
|
||||||
|
if (p_node_data.type == TYPE_INSTANTIATED) { // For the (root) nodes of sub-scenes, treat them as parts of the sub-scenes.
|
||||||
|
return get_remap_resource(res, p_resources_local_to_scenes, p_node->get(p_sname), base);
|
||||||
|
}
|
||||||
|
|
||||||
// Find the shared copy of the source resource.
|
// Find the shared copy of the source resource.
|
||||||
HashMap<Ref<Resource>, Ref<Resource>>::Iterator R = p_resources_local_to_scenes[base].find(res);
|
HashMap<Ref<Resource>, Ref<Resource>>::Iterator R = p_resources_local_to_scenes[base].find(res);
|
||||||
if (R) {
|
if (R) {
|
||||||
return R->value;
|
return R->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_node_data.type == TYPE_INSTANTIATED) { // For the (root) nodes of sub-scenes, treat them as parts of the sub-scenes.
|
|
||||||
return get_remap_resource(res, p_resources_local_to_scenes, p_node->get(p_sname), base);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p_edit_state == GEN_EDIT_STATE_MAIN) { // For the main scene, use the resource as is
|
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_scenes[base]);
|
res->configure_for_local_scene(base, p_resources_local_to_scenes[base]);
|
||||||
p_resources_local_to_scenes[base][res] = res;
|
p_resources_local_to_scenes[base][res] = res;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue