From 20261016a79b7c4677919ec18df94eaae5b062a5 Mon Sep 17 00:00:00 2001 From: kobewi Date: Mon, 13 Feb 2023 23:54:44 +0100 Subject: [PATCH] Fix typed array export Co-authored-by: Guilherme Sousa --- editor/editor_properties_array_dict.cpp | 72 ++++++++++++++--------- scene/resources/packed_scene.cpp | 77 +++++++++++++++++++++---- scene/resources/packed_scene.h | 2 + 3 files changed, 113 insertions(+), 38 deletions(-) diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index f7c789a4534..be66fbafac7 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -38,34 +38,48 @@ #include "editor/gui/editor_spin_slider.h" #include "editor/inspector_dock.h" #include "scene/gui/button.h" +#include "scene/resources/packed_scene.h" bool EditorPropertyArrayObject::_set(const StringName &p_name, const Variant &p_value) { String name = p_name; - if (name.begins_with("indices")) { - int index = name.get_slicec('/', 1).to_int(); - array.set(index, p_value); - return true; + if (!name.begins_with("indices") && !name.begins_with(PackedScene::META_POINTER_PROPERTY_BASE + "indices")) { + return false; } - return false; + int index; + if (name.begins_with("metadata/")) { + index = name.get_slice("/", 2).to_int(); + } else { + index = name.get_slice("/", 1).to_int(); + } + + array.set(index, p_value); + return true; } bool EditorPropertyArrayObject::_get(const StringName &p_name, Variant &r_ret) const { String name = p_name; - if (name.begins_with("indices")) { - int index = name.get_slicec('/', 1).to_int(); - bool valid; - r_ret = array.get(index, &valid); - if (r_ret.get_type() == Variant::OBJECT && Object::cast_to(r_ret)) { - r_ret = Object::cast_to(r_ret)->get_object_id(); - } - - return valid; + if (!name.begins_with("indices") && !name.begins_with(PackedScene::META_POINTER_PROPERTY_BASE + "indices")) { + return false; } - return false; + int index; + if (name.begins_with("metadata/")) { + index = name.get_slice("/", 2).to_int(); + } else { + index = name.get_slice("/", 1).to_int(); + } + + bool valid; + r_ret = array.get(index, &valid); + + if (r_ret.get_type() == Variant::OBJECT && Object::cast_to(r_ret)) { + r_ret = Object::cast_to(r_ret)->get_object_id(); + } + + return valid; } void EditorPropertyArrayObject::set_array(const Variant &p_array) { @@ -178,15 +192,22 @@ void EditorPropertyArray::initialize_array(Variant &p_array) { } void EditorPropertyArray::_property_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing) { - if (p_property.begins_with("indices")) { - int index = p_property.get_slice("/", 1).to_int(); - - Variant array = object->get_array().duplicate(); - array.set(index, p_value); - - object->set_array(array); - emit_changed(get_edited_property(), array, "", true); + if (!p_property.begins_with("indices") && !p_property.begins_with(PackedScene::META_POINTER_PROPERTY_BASE + "indices")) { + return; } + + int index; + if (p_property.begins_with("metadata/")) { + index = p_property.get_slice("/", 2).to_int(); + } else { + index = p_property.get_slice("/", 1).to_int(); + } + + Array array; + array.assign(object->get_array().duplicate()); + array.set(index, p_value); + object->set_array(array); + emit_changed(get_edited_property(), array, "", true); } void EditorPropertyArray::_change_type(Object *p_button, int p_index) { @@ -690,11 +711,6 @@ EditorPropertyArray::EditorPropertyArray() { add_child(edit); add_focusable(edit); - container = nullptr; - property_vbox = nullptr; - size_slider = nullptr; - button_add_item = nullptr; - paginator = nullptr; change_type = memnew(PopupMenu); add_child(change_type); change_type->connect("id_pressed", callable_mp(this, &EditorPropertyArray::_change_type_menu)); diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index 1e9038139e7..a1e7558653b 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -44,7 +44,9 @@ #include "scene/property_utils.h" #define PACKED_SCENE_VERSION 3 -#define META_POINTER_PROPERTY_BASE "metadata/_editor_prop_ptr_" + +const String PackedScene::META_POINTER_PROPERTY_BASE = "metadata/_editor_prop_ptr_"; + bool SceneState::can_instantiate() const { return nodes.size() > 0; } @@ -239,15 +241,38 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const { if (nprops[j].name & FLAG_PATH_PROPERTY_IS_NODE) { uint32_t name_idx = nprops[j].name & (FLAG_PATH_PROPERTY_IS_NODE - 1); ERR_FAIL_UNSIGNED_INDEX_V(name_idx, (uint32_t)sname_count, nullptr); - if (Engine::get_singleton()->is_editor_hint()) { - // If editor, just set the metadata and be it - node->set(META_POINTER_PROPERTY_BASE + String(snames[name_idx]), props[nprops[j].value]); + + const StringName &prop_name = snames[name_idx]; + const Variant &prop_variant = props[nprops[j].value]; + + if (prop_variant.get_type() == Variant::ARRAY) { + if (Engine::get_singleton()->is_editor_hint()) { + // If editor, simply set the original array of NodePaths. + node->set(prop_name, prop_variant); + continue; + } + + const Array &array = prop_variant; + for (int k = 0; k < array.size(); k++) { + DeferredNodePathProperties dnp; + dnp.path = array[k]; + dnp.base = node; + // Use special property name to signify an array. This is only used in deferred_node_paths. + dnp.property = String(prop_name) + "/indices/" + itos(k); + deferred_node_paths.push_back(dnp); + } + } else { + if (Engine::get_singleton()->is_editor_hint()) { + // If editor, just set the metadata and be it. + node->set(PackedScene::META_POINTER_PROPERTY_BASE + String(prop_name), prop_variant); + continue; + } // Do an actual deferred sed of the property path. DeferredNodePathProperties dnp; - dnp.path = props[nprops[j].value]; + dnp.path = prop_variant; dnp.base = node; - dnp.property = snames[name_idx]; + dnp.property = prop_name; deferred_node_paths.push_back(dnp); } continue; @@ -415,8 +440,26 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const { } for (const DeferredNodePathProperties &dnp : deferred_node_paths) { + // Replace properties stored as NodePaths with actual Nodes. Node *other = dnp.base->get_node_or_null(dnp.path); - dnp.base->set(dnp.property, other); + + const String string_property = dnp.property; + if (string_property.contains("/indices/")) { + // For properties with "/indices/", the replacement takes place inside an Array. + const String base_property = string_property.get_slice("/", 0); + const int index = string_property.get_slice("/", 2).to_int(); + + Array array = dnp.base->get(base_property); + if (array.size() >= index) { + array.push_back(other); + } else { + array.set(index, other); + } + + dnp.base->set(base_property, array); + } else { + dnp.base->set(dnp.property, other); + } } for (KeyValue, Ref> &E : resources_local_to_scene) { @@ -584,7 +627,7 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has if (E.name == META_PROPERTY_MISSING_RESOURCES) { continue; // Ignore this property when packing. } - if (E.name.begins_with(META_POINTER_PROPERTY_BASE)) { + if (E.name.begins_with(PackedScene::META_POINTER_PROPERTY_BASE)) { continue; // do not save. } @@ -600,7 +643,7 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has bool use_deferred_node_path_bit = false; if (E.type == Variant::OBJECT && E.hint == PROPERTY_HINT_NODE_TYPE) { - value = p_node->get(META_POINTER_PROPERTY_BASE + E.name); + value = p_node->get(PackedScene::META_POINTER_PROPERTY_BASE + E.name); if (value.get_type() != Variant::NODE_PATH) { continue; //was never set, ignore. } @@ -611,6 +654,20 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has if (ures.is_null()) { value = missing_resource_properties[E.name]; } + } else if (E.type == Variant::ARRAY && E.hint == PROPERTY_HINT_TYPE_STRING) { + int hint_subtype_separator = E.hint_string.find(":"); + if (hint_subtype_separator >= 0) { + String subtype_string = E.hint_string.substr(0, hint_subtype_separator); + int slash_pos = subtype_string.find("/"); + PropertyHint subtype_hint = PropertyHint::PROPERTY_HINT_NONE; + if (slash_pos >= 0) { + subtype_hint = PropertyHint(subtype_string.get_slice("/", 1).to_int()); + subtype_string = subtype_string.substr(0, slash_pos); + } + Variant::Type subtype = Variant::Type(subtype_string.to_int()); + + use_deferred_node_path_bit = subtype == Variant::OBJECT && subtype_hint == PROPERTY_HINT_NODE_TYPE; + } } if (!pinned_props.has(name)) { @@ -1736,7 +1793,7 @@ void SceneState::add_editable_instance(const NodePath &p_path) { } String SceneState::get_meta_pointer_property(const String &p_property) { - return META_POINTER_PROPERTY_BASE + p_property; + return PackedScene::META_POINTER_PROPERTY_BASE + p_property; } Vector SceneState::_get_node_groups(int p_idx) const { diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h index 5c53ffdb456..1967deab367 100644 --- a/scene/resources/packed_scene.h +++ b/scene/resources/packed_scene.h @@ -221,6 +221,8 @@ protected: virtual void reset_state() override; public: + static const String META_POINTER_PROPERTY_BASE; + enum GenEditState { GEN_EDIT_STATE_DISABLED, GEN_EDIT_STATE_INSTANCE,