@@ -327,44 +327,43 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
327
327
// handle resources that are local to scene by duplicating them if needed
328
328
Ref<Resource> res = value;
329
329
if (res.is_valid ()) {
330
- if (res->is_local_to_scene ()) {
331
- if (n.instance >= 0 ) { // For the root node of a sub-scene, treat it as part of the sub-scene.
332
- value = get_remap_resource (res, resources_local_to_sub_scene, node->get (snames[nprops[j].name ]), node);
333
- } else {
334
- HashMap<Ref<Resource>, Ref<Resource>>::Iterator E = resources_local_to_scene.find (res);
335
- Node *base = i == 0 ? node : ret_nodes[0 ];
336
- if (E) {
337
- value = E->value ;
338
- } else {
339
- if (p_edit_state == GEN_EDIT_STATE_MAIN) {
340
- // for the main scene, use the resource as is
341
- res->configure_for_local_scene (base, resources_local_to_scene);
342
- resources_local_to_scene[res] = res;
343
- } else {
344
- // for instances, a copy must be made
345
- Ref<Resource> local_dupe = res->duplicate_for_local_scene (base, resources_local_to_scene);
346
- resources_local_to_scene[res] = local_dupe;
347
- value = local_dupe;
348
- }
349
- }
350
- }
351
- // must make a copy, because this res is local to scene
352
- }
330
+ value = make_local_resource (value, n, resources_local_to_sub_scene, node, snames[nprops[j].name ], resources_local_to_scene, i, ret_nodes, p_edit_state);
353
331
}
354
332
}
355
333
if (value.get_type () == Variant::ARRAY) {
356
334
Array set_array = value;
335
+ value = setup_resources_in_array (set_array, n, resources_local_to_sub_scene, node, snames[nprops[j].name ], resources_local_to_scene, i, ret_nodes, p_edit_state);
336
+
357
337
bool is_get_valid = false ;
358
338
Variant get_value = node->get (snames[nprops[j].name ], &is_get_valid);
339
+
359
340
if (is_get_valid && get_value.get_type () == Variant::ARRAY) {
360
341
Array get_array = get_value;
361
342
if (!set_array.is_same_typed (get_array)) {
362
343
value = Array (set_array, get_array.get_typed_builtin (), get_array.get_typed_class_name (), get_array.get_typed_script ());
363
344
}
364
345
}
365
346
}
366
- if (p_edit_state == GEN_EDIT_STATE_INSTANCE && value.get_type () != Variant::OBJECT) {
367
- value = value.duplicate (true ); // Duplicate arrays and dictionaries for the editor
347
+ if (value.get_type () == Variant::DICTIONARY) {
348
+ Dictionary dictionary = value;
349
+ const Array keys = dictionary.keys ();
350
+ const Array values = dictionary.values ();
351
+
352
+ if (has_local_resource (values) || has_local_resource (keys)) {
353
+ Array duplicated_keys = keys.duplicate (true );
354
+ Array duplicated_values = values.duplicate (true );
355
+
356
+ duplicated_keys = setup_resources_in_array (duplicated_keys, n, resources_local_to_sub_scene, node, snames[nprops[j].name ], resources_local_to_scene, i, ret_nodes, p_edit_state);
357
+ duplicated_values = setup_resources_in_array (duplicated_values, n, resources_local_to_sub_scene, node, snames[nprops[j].name ], resources_local_to_scene, i, ret_nodes, p_edit_state);
358
+
359
+ dictionary.clear ();
360
+
361
+ for (int dictionary_index = 0 ; dictionary_index < keys.size (); dictionary_index++) {
362
+ dictionary[duplicated_keys[dictionary_index]] = duplicated_values[dictionary_index];
363
+ }
364
+
365
+ value = dictionary;
366
+ }
368
367
}
369
368
370
369
bool set_valid = true ;
@@ -379,6 +378,9 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
379
378
if (set_valid) {
380
379
node->set (snames[nprops[j].name ], value, &valid);
381
380
}
381
+ if (p_edit_state == GEN_EDIT_STATE_INSTANCE && value.get_type () != Variant::OBJECT) {
382
+ value = value.duplicate (true ); // Duplicate arrays and dictionaries for the editor.
383
+ }
382
384
}
383
385
}
384
386
if (!missing_resource_properties.is_empty ()) {
@@ -566,6 +568,50 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
566
568
return ret_nodes[0 ];
567
569
}
568
570
571
+ Variant SceneState::make_local_resource (Variant &p_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 {
572
+ Ref<Resource> res = p_value;
573
+ if (res.is_null () || !res->is_local_to_scene ()) {
574
+ return p_value;
575
+ }
576
+
577
+ if (p_node_data.instance >= 0 ) { // For the root node of a sub-scene, treat it as part of the sub-scene.
578
+ return get_remap_resource (res, p_resources_local_to_sub_scene, p_node->get (p_sname), p_node);
579
+ } else {
580
+ HashMap<Ref<Resource>, Ref<Resource>>::Iterator E = p_resources_local_to_scene.find (res);
581
+ Node *base = p_i == 0 ? p_node : p_ret_nodes[0 ];
582
+ if (E) {
583
+ return E->value ;
584
+ } else if (p_edit_state == GEN_EDIT_STATE_MAIN) { // For the main scene, use the resource as is
585
+ res->configure_for_local_scene (base, p_resources_local_to_scene);
586
+ p_resources_local_to_scene[res] = res;
587
+ return res;
588
+ } else { // For instances, a copy must be made.
589
+ Ref<Resource> local_dupe = res->duplicate_for_local_scene (base, p_resources_local_to_scene);
590
+ p_resources_local_to_scene[res] = local_dupe;
591
+ return local_dupe;
592
+ }
593
+ }
594
+ }
595
+
596
+ Array SceneState::setup_resources_in_array (Array &p_array_to_scan, const SceneState::NodeData &p_n, 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 {
597
+ for (int i = 0 ; i < p_array_to_scan.size (); i++) {
598
+ if (p_array_to_scan[i].get_type () == Variant::OBJECT) {
599
+ p_array_to_scan[i] = make_local_resource (p_array_to_scan[i], p_n, p_resources_local_to_sub_scene, p_node, p_sname, p_resources_local_to_scene, p_i, p_ret_nodes, p_edit_state);
600
+ }
601
+ }
602
+ return p_array_to_scan;
603
+ }
604
+
605
+ bool SceneState::has_local_resource (const Array &p_array) const {
606
+ for (int i = 0 ; i < p_array.size (); i++) {
607
+ Ref<Resource> res = p_array[i];
608
+ if (res.is_valid () && res->is_local_to_scene ()) {
609
+ return true ;
610
+ }
611
+ }
612
+ return false ;
613
+ }
614
+
569
615
static int _nm_get_string (const String &p_string, HashMap<StringName, int > &name_map) {
570
616
if (name_map.has (p_string)) {
571
617
return name_map[p_string];
@@ -730,8 +776,18 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has
730
776
if (!pinned_props.has (name)) {
731
777
bool is_valid_default = false ;
732
778
Variant default_value = PropertyUtils::get_property_default_value (p_node, name, &is_valid_default, &states_stack, true );
779
+
733
780
if (is_valid_default && !PropertyUtils::is_property_value_different (value, default_value)) {
734
- continue ;
781
+ if (value.get_type () == Variant::ARRAY && has_local_resource (value)) {
782
+ // Save anyway
783
+ } else if (value.get_type () == Variant::DICTIONARY) {
784
+ Dictionary dictionary = value;
785
+ if (!has_local_resource (dictionary.values ()) && !has_local_resource (dictionary.keys ())) {
786
+ continue ;
787
+ }
788
+ } else {
789
+ continue ;
790
+ }
735
791
}
736
792
}
737
793
0 commit comments