Browse Source

Duplicate Arrays and Dictionaries when instancing scene in editor

Also, add deep (=false) parameter to Array.duplicate and Dictionary.duplicate

Fixes #13971
Bojidar Marinov 7 years ago
parent
commit
9f6c0c6eae

+ 4 - 4
core/array.cpp

@@ -35,8 +35,8 @@
 #include "variant.h"
 #include "vector.h"
 
-struct ArrayPrivate {
-
+class ArrayPrivate {
+public:
 	SafeRefCount refcount;
 	Vector<Variant> array;
 };
@@ -211,13 +211,13 @@ const Variant &Array::get(int p_idx) const {
 	return operator[](p_idx);
 }
 
-Array Array::duplicate() const {
+Array Array::duplicate(bool p_deep) const {
 
 	Array new_arr;
 	int element_count = size();
 	new_arr.resize(element_count);
 	for (int i = 0; i < element_count; i++) {
-		new_arr[i] = get(i);
+		new_arr[i] = p_deep ? get(i).duplicate(p_deep) : get(i);
 	}
 
 	return new_arr;

+ 1 - 1
core/array.h

@@ -88,7 +88,7 @@ public:
 	Variant pop_back();
 	Variant pop_front();
 
-	Array duplicate() const;
+	Array duplicate(bool p_deep = false) const;
 
 	Array(const Array &p_from);
 	Array();

+ 2 - 2
core/dictionary.cpp

@@ -211,7 +211,7 @@ const Variant *Dictionary::next(const Variant *p_key) const {
 	return NULL;
 }
 
-Dictionary Dictionary::duplicate() const {
+Dictionary Dictionary::duplicate(bool p_deep) const {
 
 	Dictionary n;
 
@@ -219,7 +219,7 @@ Dictionary Dictionary::duplicate() const {
 	get_key_list(&keys);
 
 	for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
-		n[E->get()] = operator[](E->get());
+		n[E->get()] = p_deep ? operator[](E->get()).duplicate(p_deep) : operator[](E->get());
 	}
 
 	return n;

+ 1 - 1
core/dictionary.h

@@ -75,7 +75,7 @@ public:
 	Array keys() const;
 	Array values() const;
 
-	Dictionary duplicate() const;
+	Dictionary duplicate(bool p_deep = false) const;
 
 	Dictionary(const Dictionary &p_from);
 	Dictionary();

+ 1 - 1
core/resource.cpp

@@ -226,7 +226,7 @@ Ref<Resource> Resource::duplicate(bool p_subresources) const {
 
 		if (!(E->get().usage & PROPERTY_USAGE_STORAGE))
 			continue;
-		Variant p = get(E->get().name);
+		Variant p = get(E->get().name).duplicate(true);
 		if (p.get_type() == Variant::OBJECT && p_subresources) {
 
 			RES sr = p;

+ 1 - 0
core/variant.h

@@ -338,6 +338,7 @@ public:
 	}
 
 	void zero();
+	Variant duplicate(bool deep = false) const;
 	static void blend(const Variant &a, const Variant &b, float c, Variant &r_dst);
 	static void interpolate(const Variant &a, const Variant &b, float c, Variant &r_dst);
 

+ 4 - 4
core/variant_call.cpp

@@ -465,7 +465,7 @@ struct _VariantCall {
 	VCALL_LOCALMEM0R(Dictionary, hash);
 	VCALL_LOCALMEM0R(Dictionary, keys);
 	VCALL_LOCALMEM0R(Dictionary, values);
-	VCALL_LOCALMEM0R(Dictionary, duplicate);
+	VCALL_LOCALMEM1R(Dictionary, duplicate);
 
 	VCALL_LOCALMEM2(Array, set);
 	VCALL_LOCALMEM1R(Array, get);
@@ -494,7 +494,7 @@ struct _VariantCall {
 	VCALL_LOCALMEM0(Array, shuffle);
 	VCALL_LOCALMEM2R(Array, bsearch);
 	VCALL_LOCALMEM4R(Array, bsearch_custom);
-	VCALL_LOCALMEM0R(Array, duplicate);
+	VCALL_LOCALMEM1R(Array, duplicate);
 	VCALL_LOCALMEM0(Array, invert);
 
 	static void _call_PoolByteArray_get_string_from_ascii(Variant &r_ret, Variant &p_self, const Variant **p_args) {
@@ -1613,7 +1613,7 @@ void register_variant_methods() {
 	ADDFUNC0R(DICTIONARY, INT, Dictionary, hash, varray());
 	ADDFUNC0R(DICTIONARY, ARRAY, Dictionary, keys, varray());
 	ADDFUNC0R(DICTIONARY, ARRAY, Dictionary, values, varray());
-	ADDFUNC0R(DICTIONARY, DICTIONARY, Dictionary, duplicate, varray());
+	ADDFUNC1R(DICTIONARY, DICTIONARY, Dictionary, duplicate, BOOL, "deep", varray(false));
 
 	ADDFUNC0R(ARRAY, INT, Array, size, varray());
 	ADDFUNC0R(ARRAY, BOOL, Array, empty, varray());
@@ -1641,7 +1641,7 @@ void register_variant_methods() {
 	ADDFUNC2R(ARRAY, INT, Array, bsearch, NIL, "value", BOOL, "before", varray(true));
 	ADDFUNC4R(ARRAY, INT, Array, bsearch_custom, NIL, "value", OBJECT, "obj", STRING, "func", BOOL, "before", varray(true));
 	ADDFUNC0NC(ARRAY, NIL, Array, invert, varray());
-	ADDFUNC0RNC(ARRAY, ARRAY, Array, duplicate, varray());
+	ADDFUNC1R(ARRAY, ARRAY, Array, duplicate, BOOL, "deep", varray(false));
 
 	ADDFUNC0R(POOL_BYTE_ARRAY, INT, PoolByteArray, size, varray());
 	ADDFUNC2(POOL_BYTE_ARRAY, NIL, PoolByteArray, set, INT, "idx", INT, "byte", varray());

+ 13 - 0
core/variant_op.cpp

@@ -3415,6 +3415,19 @@ Variant Variant::iter_get(const Variant &r_iter, bool &r_valid) const {
 	return Variant();
 }
 
+Variant Variant::duplicate(bool deep) const {
+	switch (type) {
+		// case OBJECT:
+		// 	return operator Object *()->duplicate();
+		case DICTIONARY:
+			return operator Dictionary().duplicate(deep);
+		case ARRAY:
+			return operator Array().duplicate(deep);
+		default:
+			return *this;
+	}
+}
+
 void Variant::blend(const Variant &a, const Variant &b, float c, Variant &r_dst) {
 	if (a.type != b.type) {
 		if (a.is_num() && b.is_num()) {

+ 1 - 1
editor/property_editor.cpp

@@ -3939,7 +3939,7 @@ void PropertyEditor::_edit_button(Object *p_item, int p_column, int p_button) {
 
 		if (_might_be_in_instance() && _get_instanced_node_original_property(prop, vorig)) {
 
-			_edit_set(prop, vorig);
+			_edit_set(prop, vorig.duplicate(true)); // Set, making sure to duplicate arrays properly
 			return;
 		}
 

+ 2 - 14
scene/main/node.cpp

@@ -2163,13 +2163,7 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const
 			if (name == script_property_name)
 				continue;
 
-			Variant value = N->get()->get(name);
-			// Duplicate dictionaries and arrays, mainly needed for __meta__
-			if (value.get_type() == Variant::DICTIONARY) {
-				value = Dictionary(value).duplicate();
-			} else if (value.get_type() == Variant::ARRAY) {
-				value = Array(value).duplicate();
-			}
+			Variant value = N->get()->get(name).duplicate(true);
 
 			if (E->get().usage & PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE) {
 
@@ -2313,13 +2307,7 @@ void Node::_duplicate_and_reown(Node *p_new_parent, const Map<Node *, Node *> &p
 			continue;
 		String name = E->get().name;
 
-		Variant value = get(name);
-		// Duplicate dictionaries and arrays, mainly needed for __meta__
-		if (value.get_type() == Variant::DICTIONARY) {
-			value = Dictionary(value).duplicate();
-		} else if (value.get_type() == Variant::ARRAY) {
-			value = Array(value).duplicate();
-		}
+		Variant value = get(name).duplicate(true);
 
 		node->set(name, value);
 	}

+ 2 - 0
scene/resources/packed_scene.cpp

@@ -249,6 +249,8 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
 									//must make a copy, because this res is local to scene
 								}
 							}
+						} else if (p_edit_state == GEN_EDIT_STATE_INSTANCE) {
+							value = value.duplicate(true); // Duplicate arrays and dictionaries for the editor
 						}
 						node->set(snames[nprops[j].name], value, &valid);
 					}