Merge pull request #62185 from reduz/export-node-pointer-path
Add ability to export Node pointers as NodePaths
This commit is contained in:
commit
fbc3777467
11 changed files with 184 additions and 36 deletions
|
@ -613,6 +613,7 @@ void register_global_constants() {
|
||||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_ARRAY_TYPE);
|
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_ARRAY_TYPE);
|
||||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LOCALE_ID);
|
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LOCALE_ID);
|
||||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LOCALIZABLE_STRING);
|
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LOCALIZABLE_STRING);
|
||||||
|
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_NODE_TYPE);
|
||||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_MAX);
|
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_MAX);
|
||||||
|
|
||||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_NONE);
|
BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_NONE);
|
||||||
|
|
|
@ -91,6 +91,7 @@ enum PropertyHint {
|
||||||
PROPERTY_HINT_INT_IS_POINTER,
|
PROPERTY_HINT_INT_IS_POINTER,
|
||||||
PROPERTY_HINT_LOCALE_ID,
|
PROPERTY_HINT_LOCALE_ID,
|
||||||
PROPERTY_HINT_LOCALIZABLE_STRING,
|
PROPERTY_HINT_LOCALIZABLE_STRING,
|
||||||
|
PROPERTY_HINT_NODE_TYPE, ///< a node object type
|
||||||
PROPERTY_HINT_MAX,
|
PROPERTY_HINT_MAX,
|
||||||
// When updating PropertyHint, also sync the hardcoded list in VisualScriptEditorVariableEdit
|
// When updating PropertyHint, also sync the hardcoded list in VisualScriptEditorVariableEdit
|
||||||
};
|
};
|
||||||
|
|
|
@ -2583,7 +2583,9 @@
|
||||||
<constant name="PROPERTY_HINT_LOCALIZABLE_STRING" value="44" enum="PropertyHint">
|
<constant name="PROPERTY_HINT_LOCALIZABLE_STRING" value="44" enum="PropertyHint">
|
||||||
Hints that a dictionary property is string translation map. Dictionary keys are locale codes and, values are translated strings.
|
Hints that a dictionary property is string translation map. Dictionary keys are locale codes and, values are translated strings.
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="PROPERTY_HINT_MAX" value="45" enum="PropertyHint">
|
<constant name="PROPERTY_HINT_NODE_TYPE" value="45" enum="PropertyHint">
|
||||||
|
</constant>
|
||||||
|
<constant name="PROPERTY_HINT_MAX" value="46" enum="PropertyHint">
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="PROPERTY_USAGE_NONE" value="0" enum="PropertyUsageFlags">
|
<constant name="PROPERTY_USAGE_NONE" value="0" enum="PropertyUsageFlags">
|
||||||
</constant>
|
</constant>
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
Gets the edited object.
|
Gets the edited object.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="get_edited_property">
|
<method name="get_edited_property" qualifiers="const">
|
||||||
<return type="StringName" />
|
<return type="StringName" />
|
||||||
<description>
|
<description>
|
||||||
Gets the edited property. If your editor is for a single property (added via [method EditorInspectorPlugin._parse_property]), then this will return the property.
|
Gets the edited property. If your editor is for a single property (added via [method EditorInspectorPlugin._parse_property]), then this will return the property.
|
||||||
|
|
|
@ -406,7 +406,7 @@ Object *EditorProperty::get_edited_object() {
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringName EditorProperty::get_edited_property() {
|
StringName EditorProperty::get_edited_property() const {
|
||||||
return property;
|
return property;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -437,16 +437,20 @@ Variant EditorPropertyRevert::get_property_revert_value(Object *p_object, const
|
||||||
return PropertyUtils::get_property_default_value(p_object, p_property, r_is_valid);
|
return PropertyUtils::get_property_default_value(p_object, p_property, r_is_valid);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EditorPropertyRevert::can_property_revert(Object *p_object, const StringName &p_property) {
|
bool EditorPropertyRevert::can_property_revert(Object *p_object, const StringName &p_property, const Variant *p_custom_current_value) {
|
||||||
bool is_valid_revert = false;
|
bool is_valid_revert = false;
|
||||||
Variant revert_value = EditorPropertyRevert::get_property_revert_value(p_object, p_property, &is_valid_revert);
|
Variant revert_value = EditorPropertyRevert::get_property_revert_value(p_object, p_property, &is_valid_revert);
|
||||||
if (!is_valid_revert) {
|
if (!is_valid_revert) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Variant current_value = p_object->get(p_property);
|
Variant current_value = p_custom_current_value ? *p_custom_current_value : p_object->get(p_property);
|
||||||
return PropertyUtils::is_property_value_different(current_value, revert_value);
|
return PropertyUtils::is_property_value_different(current_value, revert_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StringName EditorProperty::_get_revert_property() const {
|
||||||
|
return property;
|
||||||
|
}
|
||||||
|
|
||||||
void EditorProperty::update_revert_and_pin_status() {
|
void EditorProperty::update_revert_and_pin_status() {
|
||||||
if (property == StringName()) {
|
if (property == StringName()) {
|
||||||
return; //no property, so nothing to do
|
return; //no property, so nothing to do
|
||||||
|
@ -458,7 +462,8 @@ void EditorProperty::update_revert_and_pin_status() {
|
||||||
CRASH_COND(!node);
|
CRASH_COND(!node);
|
||||||
new_pinned = node->is_property_pinned(property);
|
new_pinned = node->is_property_pinned(property);
|
||||||
}
|
}
|
||||||
bool new_can_revert = EditorPropertyRevert::can_property_revert(object, property) && !is_read_only();
|
Variant current = object->get(_get_revert_property());
|
||||||
|
bool new_can_revert = EditorPropertyRevert::can_property_revert(object, property, ¤t) && !is_read_only();
|
||||||
|
|
||||||
if (new_can_revert != can_revert || new_pinned != pinned) {
|
if (new_can_revert != can_revert || new_pinned != pinned) {
|
||||||
can_revert = new_can_revert;
|
can_revert = new_can_revert;
|
||||||
|
@ -717,11 +722,15 @@ void EditorProperty::set_bottom_editor(Control *p_control) {
|
||||||
bottom_editor = p_control;
|
bottom_editor = p_control;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Variant EditorProperty::_get_cache_value(const StringName &p_prop, bool &r_valid) const {
|
||||||
|
return object->get(p_prop, &r_valid);
|
||||||
|
}
|
||||||
|
|
||||||
bool EditorProperty::is_cache_valid() const {
|
bool EditorProperty::is_cache_valid() const {
|
||||||
if (object) {
|
if (object) {
|
||||||
for (const KeyValue<StringName, Variant> &E : cache) {
|
for (const KeyValue<StringName, Variant> &E : cache) {
|
||||||
bool valid;
|
bool valid;
|
||||||
Variant value = object->get(E.key, &valid);
|
Variant value = _get_cache_value(E.key, valid);
|
||||||
if (!valid || value != E.value) {
|
if (!valid || value != E.value) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -733,7 +742,7 @@ void EditorProperty::update_cache() {
|
||||||
cache.clear();
|
cache.clear();
|
||||||
if (object && property != StringName()) {
|
if (object && property != StringName()) {
|
||||||
bool valid;
|
bool valid;
|
||||||
Variant value = object->get(property, &valid);
|
Variant value = _get_cache_value(property, valid);
|
||||||
if (valid) {
|
if (valid) {
|
||||||
cache[property] = value;
|
cache[property] = value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ public:
|
||||||
static bool is_property_value_different(const Variant &p_a, const Variant &p_b);
|
static bool is_property_value_different(const Variant &p_a, const Variant &p_b);
|
||||||
static Variant get_property_revert_value(Object *p_object, const StringName &p_property, bool *r_is_valid);
|
static Variant get_property_revert_value(Object *p_object, const StringName &p_property, bool *r_is_valid);
|
||||||
|
|
||||||
static bool can_property_revert(Object *p_object, const StringName &p_property);
|
static bool can_property_revert(Object *p_object, const StringName &p_property, const Variant *p_custom_current_value = nullptr);
|
||||||
};
|
};
|
||||||
|
|
||||||
class EditorProperty : public Container {
|
class EditorProperty : public Container {
|
||||||
|
@ -131,6 +131,9 @@ protected:
|
||||||
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
|
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
|
||||||
const Color *_get_property_colors();
|
const Color *_get_property_colors();
|
||||||
|
|
||||||
|
virtual Variant _get_cache_value(const StringName &p_prop, bool &r_valid) const;
|
||||||
|
virtual StringName _get_revert_property() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void emit_changed(const StringName &p_property, const Variant &p_value, const StringName &p_field = StringName(), bool p_changing = false);
|
void emit_changed(const StringName &p_property, const Variant &p_value, const StringName &p_field = StringName(), bool p_changing = false);
|
||||||
|
|
||||||
|
@ -143,7 +146,7 @@ public:
|
||||||
bool is_read_only() const;
|
bool is_read_only() const;
|
||||||
|
|
||||||
Object *get_edited_object();
|
Object *get_edited_object();
|
||||||
StringName get_edited_property();
|
StringName get_edited_property() const;
|
||||||
|
|
||||||
virtual void update_property();
|
virtual void update_property();
|
||||||
void update_revert_and_pin_status();
|
void update_revert_and_pin_status();
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
#include "scene/main/window.h"
|
#include "scene/main/window.h"
|
||||||
#include "scene/resources/font.h"
|
#include "scene/resources/font.h"
|
||||||
#include "scene/resources/mesh.h"
|
#include "scene/resources/mesh.h"
|
||||||
|
#include "scene/resources/packed_scene.h"
|
||||||
|
|
||||||
///////////////////// Nil /////////////////////////
|
///////////////////// Nil /////////////////////////
|
||||||
|
|
||||||
|
@ -3017,6 +3018,23 @@ void EditorPropertyNodePath::_set_read_only(bool p_read_only) {
|
||||||
clear->set_disabled(p_read_only);
|
clear->set_disabled(p_read_only);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
String EditorPropertyNodePath::_get_meta_pointer_property() const {
|
||||||
|
ERR_FAIL_COND_V(!pointer_mode, String());
|
||||||
|
return SceneState::get_meta_pointer_property(get_edited_property());
|
||||||
|
}
|
||||||
|
|
||||||
|
Variant EditorPropertyNodePath::_get_cache_value(const StringName &p_prop, bool &r_valid) const {
|
||||||
|
if (p_prop == get_edited_property()) {
|
||||||
|
r_valid = true;
|
||||||
|
return const_cast<EditorPropertyNodePath *>(this)->get_edited_object()->get(_get_meta_pointer_property(), &r_valid);
|
||||||
|
}
|
||||||
|
return Variant();
|
||||||
|
}
|
||||||
|
|
||||||
|
StringName EditorPropertyNodePath::_get_revert_property() const {
|
||||||
|
return _get_meta_pointer_property();
|
||||||
|
}
|
||||||
|
|
||||||
void EditorPropertyNodePath::_node_selected(const NodePath &p_path) {
|
void EditorPropertyNodePath::_node_selected(const NodePath &p_path) {
|
||||||
NodePath path = p_path;
|
NodePath path = p_path;
|
||||||
Node *base_node = nullptr;
|
Node *base_node = nullptr;
|
||||||
|
@ -3048,7 +3066,11 @@ void EditorPropertyNodePath::_node_selected(const NodePath &p_path) {
|
||||||
if (base_node) { // for AnimationTrackKeyEdit
|
if (base_node) { // for AnimationTrackKeyEdit
|
||||||
path = base_node->get_path().rel_path_to(p_path);
|
path = base_node->get_path().rel_path_to(p_path);
|
||||||
}
|
}
|
||||||
emit_changed(get_edited_property(), path);
|
if (pointer_mode && base_node) {
|
||||||
|
emit_changed(_get_meta_pointer_property(), path);
|
||||||
|
} else {
|
||||||
|
emit_changed(get_edited_property(), path);
|
||||||
|
}
|
||||||
update_property();
|
update_property();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3064,7 +3086,11 @@ void EditorPropertyNodePath::_node_assign() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorPropertyNodePath::_node_clear() {
|
void EditorPropertyNodePath::_node_clear() {
|
||||||
emit_changed(get_edited_property(), NodePath());
|
if (pointer_mode) {
|
||||||
|
emit_changed(_get_meta_pointer_property(), NodePath());
|
||||||
|
} else {
|
||||||
|
emit_changed(get_edited_property(), NodePath());
|
||||||
|
}
|
||||||
update_property();
|
update_property();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3092,7 +3118,12 @@ bool EditorPropertyNodePath::is_drop_valid(const Dictionary &p_drag_data) const
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorPropertyNodePath::update_property() {
|
void EditorPropertyNodePath::update_property() {
|
||||||
NodePath p = get_edited_object()->get(get_edited_property());
|
NodePath p;
|
||||||
|
if (pointer_mode) {
|
||||||
|
p = get_edited_object()->get(_get_meta_pointer_property());
|
||||||
|
} else {
|
||||||
|
p = get_edited_object()->get(get_edited_property());
|
||||||
|
}
|
||||||
|
|
||||||
assign->set_tooltip(p);
|
assign->set_tooltip(p);
|
||||||
if (p == NodePath()) {
|
if (p == NodePath()) {
|
||||||
|
@ -3131,7 +3162,8 @@ void EditorPropertyNodePath::update_property() {
|
||||||
assign->set_icon(EditorNode::get_singleton()->get_object_icon(target_node, "Node"));
|
assign->set_icon(EditorNode::get_singleton()->get_object_icon(target_node, "Node"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorPropertyNodePath::setup(const NodePath &p_base_hint, Vector<StringName> p_valid_types, bool p_use_path_from_scene_root) {
|
void EditorPropertyNodePath::setup(const NodePath &p_base_hint, Vector<StringName> p_valid_types, bool p_use_path_from_scene_root, bool p_pointer_mode) {
|
||||||
|
pointer_mode = p_pointer_mode;
|
||||||
base_hint = p_base_hint;
|
base_hint = p_base_hint;
|
||||||
valid_types = p_valid_types;
|
valid_types = p_valid_types;
|
||||||
use_path_from_scene_root = p_use_path_from_scene_root;
|
use_path_from_scene_root = p_use_path_from_scene_root;
|
||||||
|
@ -3927,23 +3959,31 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
|
||||||
return editor;
|
return editor;
|
||||||
} break;
|
} break;
|
||||||
case Variant::OBJECT: {
|
case Variant::OBJECT: {
|
||||||
EditorPropertyResource *editor = memnew(EditorPropertyResource);
|
if (p_hint == PROPERTY_HINT_NODE_TYPE) {
|
||||||
editor->setup(p_object, p_path, p_hint == PROPERTY_HINT_RESOURCE_TYPE ? p_hint_text : "Resource");
|
EditorPropertyNodePath *editor = memnew(EditorPropertyNodePath);
|
||||||
|
Vector<String> types = p_hint_text.split(",", false);
|
||||||
|
Vector<StringName> sn = Variant(types); //convert via variant
|
||||||
|
editor->setup(NodePath(), sn, false, true);
|
||||||
|
return editor;
|
||||||
|
} else {
|
||||||
|
EditorPropertyResource *editor = memnew(EditorPropertyResource);
|
||||||
|
editor->setup(p_object, p_path, p_hint == PROPERTY_HINT_RESOURCE_TYPE ? p_hint_text : "Resource");
|
||||||
|
|
||||||
if (p_hint == PROPERTY_HINT_RESOURCE_TYPE) {
|
if (p_hint == PROPERTY_HINT_RESOURCE_TYPE) {
|
||||||
String open_in_new = EDITOR_GET("interface/inspector/resources_to_open_in_new_inspector");
|
String open_in_new = EDITOR_GET("interface/inspector/resources_to_open_in_new_inspector");
|
||||||
for (int i = 0; i < open_in_new.get_slice_count(","); i++) {
|
for (int i = 0; i < open_in_new.get_slice_count(","); i++) {
|
||||||
String type = open_in_new.get_slicec(',', i).strip_edges();
|
String type = open_in_new.get_slicec(',', i).strip_edges();
|
||||||
for (int j = 0; j < p_hint_text.get_slice_count(","); j++) {
|
for (int j = 0; j < p_hint_text.get_slice_count(","); j++) {
|
||||||
String inherits = p_hint_text.get_slicec(',', j);
|
String inherits = p_hint_text.get_slicec(',', j);
|
||||||
if (ClassDB::is_parent_class(inherits, type)) {
|
if (ClassDB::is_parent_class(inherits, type)) {
|
||||||
editor->set_use_sub_inspector(false);
|
editor->set_use_sub_inspector(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return editor;
|
return editor;
|
||||||
|
}
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case Variant::DICTIONARY: {
|
case Variant::DICTIONARY: {
|
||||||
|
|
|
@ -704,6 +704,7 @@ class EditorPropertyNodePath : public EditorProperty {
|
||||||
SceneTreeDialog *scene_tree = nullptr;
|
SceneTreeDialog *scene_tree = nullptr;
|
||||||
NodePath base_hint;
|
NodePath base_hint;
|
||||||
bool use_path_from_scene_root = false;
|
bool use_path_from_scene_root = false;
|
||||||
|
bool pointer_mode = false;
|
||||||
|
|
||||||
Vector<StringName> valid_types;
|
Vector<StringName> valid_types;
|
||||||
void _node_selected(const NodePath &p_path);
|
void _node_selected(const NodePath &p_path);
|
||||||
|
@ -714,6 +715,10 @@ class EditorPropertyNodePath : public EditorProperty {
|
||||||
void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
|
void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
|
||||||
bool is_drop_valid(const Dictionary &p_drag_data) const;
|
bool is_drop_valid(const Dictionary &p_drag_data) const;
|
||||||
|
|
||||||
|
String _get_meta_pointer_property() const;
|
||||||
|
virtual Variant _get_cache_value(const StringName &p_prop, bool &r_valid) const override;
|
||||||
|
virtual StringName _get_revert_property() const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void _set_read_only(bool p_read_only) override;
|
virtual void _set_read_only(bool p_read_only) override;
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
@ -721,7 +726,7 @@ protected:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void update_property() override;
|
virtual void update_property() override;
|
||||||
void setup(const NodePath &p_base_hint, Vector<StringName> p_valid_types, bool p_use_path_from_scene_root = true);
|
void setup(const NodePath &p_base_hint, Vector<StringName> p_valid_types, bool p_use_path_from_scene_root = true, bool p_pointer_mode = false);
|
||||||
EditorPropertyNodePath();
|
EditorPropertyNodePath();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include "core/core_string_names.h"
|
#include "core/core_string_names.h"
|
||||||
#include "core/io/missing_resource.h"
|
#include "core/io/missing_resource.h"
|
||||||
#include "core/io/resource_loader.h"
|
#include "core/io/resource_loader.h"
|
||||||
|
#include "core/templates/local_vector.h"
|
||||||
#include "scene/2d/node_2d.h"
|
#include "scene/2d/node_2d.h"
|
||||||
#include "scene/3d/node_3d.h"
|
#include "scene/3d/node_3d.h"
|
||||||
#include "scene/gui/control.h"
|
#include "scene/gui/control.h"
|
||||||
|
@ -43,7 +44,7 @@
|
||||||
#include "scene/property_utils.h"
|
#include "scene/property_utils.h"
|
||||||
|
|
||||||
#define PACKED_SCENE_VERSION 2
|
#define PACKED_SCENE_VERSION 2
|
||||||
|
#define META_POINTER_PROPERTY_BASE "metadata/_editor_prop_ptr_"
|
||||||
bool SceneState::can_instantiate() const {
|
bool SceneState::can_instantiate() const {
|
||||||
return nodes.size() > 0;
|
return nodes.size() > 0;
|
||||||
}
|
}
|
||||||
|
@ -108,6 +109,8 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
|
||||||
|
|
||||||
HashMap<Ref<Resource>, Ref<Resource>> resources_local_to_scene;
|
HashMap<Ref<Resource>, Ref<Resource>> resources_local_to_scene;
|
||||||
|
|
||||||
|
LocalVector<DeferredNodePathProperties> deferred_node_paths;
|
||||||
|
|
||||||
for (int i = 0; i < nc; i++) {
|
for (int i = 0; i < nc; i++) {
|
||||||
const NodeData &n = nd[i];
|
const NodeData &n = nd[i];
|
||||||
|
|
||||||
|
@ -230,9 +233,28 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
|
||||||
|
|
||||||
for (int j = 0; j < nprop_count; j++) {
|
for (int j = 0; j < nprop_count; j++) {
|
||||||
bool valid;
|
bool valid;
|
||||||
ERR_FAIL_INDEX_V(nprops[j].name, sname_count, nullptr);
|
|
||||||
ERR_FAIL_INDEX_V(nprops[j].value, prop_count, nullptr);
|
ERR_FAIL_INDEX_V(nprops[j].value, prop_count, nullptr);
|
||||||
|
|
||||||
|
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]);
|
||||||
|
} else {
|
||||||
|
// Do an actual deferred sed of the property path.
|
||||||
|
DeferredNodePathProperties dnp;
|
||||||
|
dnp.path = props[nprops[j].value];
|
||||||
|
dnp.base = node;
|
||||||
|
dnp.property = snames[name_idx];
|
||||||
|
deferred_node_paths.push_back(dnp);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ERR_FAIL_INDEX_V(nprops[j].name, sname_count, nullptr);
|
||||||
|
|
||||||
if (snames[nprops[j].name] == CoreStringNames::get_singleton()->_script) {
|
if (snames[nprops[j].name] == CoreStringNames::get_singleton()->_script) {
|
||||||
//work around to avoid old script variables from disappearing, should be the proper fix to:
|
//work around to avoid old script variables from disappearing, should be the proper fix to:
|
||||||
//https://github.com/godotengine/godot/issues/2958
|
//https://github.com/godotengine/godot/issues/2958
|
||||||
|
@ -369,6 +391,12 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < deferred_node_paths.size(); i++) {
|
||||||
|
const DeferredNodePathProperties &dnp = deferred_node_paths[i];
|
||||||
|
Node *other = dnp.base->get_node_or_null(dnp.path);
|
||||||
|
dnp.base->set(dnp.property, other);
|
||||||
|
}
|
||||||
|
|
||||||
for (KeyValue<Ref<Resource>, Ref<Resource>> &E : resources_local_to_scene) {
|
for (KeyValue<Ref<Resource>, Ref<Resource>> &E : resources_local_to_scene) {
|
||||||
E.value->setup_local_to_scene();
|
E.value->setup_local_to_scene();
|
||||||
}
|
}
|
||||||
|
@ -532,6 +560,9 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has
|
||||||
if (E.name == META_PROPERTY_MISSING_RESOURCES) {
|
if (E.name == META_PROPERTY_MISSING_RESOURCES) {
|
||||||
continue; // Ignore this property when packing.
|
continue; // Ignore this property when packing.
|
||||||
}
|
}
|
||||||
|
if (E.name.begins_with(META_POINTER_PROPERTY_BASE)) {
|
||||||
|
continue; // do not save.
|
||||||
|
}
|
||||||
|
|
||||||
// If instance or inheriting, not saving if property requested so.
|
// If instance or inheriting, not saving if property requested so.
|
||||||
if (!states_stack.is_empty()) {
|
if (!states_stack.is_empty()) {
|
||||||
|
@ -542,8 +573,15 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has
|
||||||
|
|
||||||
StringName name = E.name;
|
StringName name = E.name;
|
||||||
Variant value = p_node->get(name);
|
Variant value = p_node->get(name);
|
||||||
|
bool use_deferred_node_path_bit = false;
|
||||||
|
|
||||||
if (E.type == Variant::OBJECT && missing_resource_properties.has(E.name)) {
|
if (E.type == Variant::OBJECT && E.hint == PROPERTY_HINT_NODE_TYPE) {
|
||||||
|
value = p_node->get(META_POINTER_PROPERTY_BASE + E.name);
|
||||||
|
if (value.get_type() != Variant::NODE_PATH) {
|
||||||
|
continue; //was never set, ignore.
|
||||||
|
}
|
||||||
|
use_deferred_node_path_bit = true;
|
||||||
|
} else if (E.type == Variant::OBJECT && missing_resource_properties.has(E.name)) {
|
||||||
// Was this missing resource overridden? If so do not save the old value.
|
// Was this missing resource overridden? If so do not save the old value.
|
||||||
Ref<Resource> ures = value;
|
Ref<Resource> ures = value;
|
||||||
if (ures.is_null()) {
|
if (ures.is_null()) {
|
||||||
|
@ -562,6 +600,9 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has
|
||||||
NodeData::Property prop;
|
NodeData::Property prop;
|
||||||
prop.name = _nm_get_string(name, name_map);
|
prop.name = _nm_get_string(name, name_map);
|
||||||
prop.value = _vm_get_variant(value, variant_map);
|
prop.value = _vm_get_variant(value, variant_map);
|
||||||
|
if (use_deferred_node_path_bit) {
|
||||||
|
prop.name |= FLAG_PATH_PROPERTY_IS_NODE;
|
||||||
|
}
|
||||||
nd.properties.push_back(prop);
|
nd.properties.push_back(prop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1018,7 +1059,7 @@ Variant SceneState::get_property_value(int p_node, const StringName &p_property,
|
||||||
|
|
||||||
const NodeData::Property *p = nodes[p_node].properties.ptr();
|
const NodeData::Property *p = nodes[p_node].properties.ptr();
|
||||||
for (int i = 0; i < pc; i++) {
|
for (int i = 0; i < pc; i++) {
|
||||||
if (p_property == namep[p[i].name]) {
|
if (p_property == namep[p[i].name & FLAG_PROP_NAME_MASK]) {
|
||||||
found = true;
|
found = true;
|
||||||
return variants[p[i].value];
|
return variants[p[i].value];
|
||||||
}
|
}
|
||||||
|
@ -1409,7 +1450,19 @@ int SceneState::get_node_property_count(int p_idx) const {
|
||||||
StringName SceneState::get_node_property_name(int p_idx, int p_prop) const {
|
StringName SceneState::get_node_property_name(int p_idx, int p_prop) const {
|
||||||
ERR_FAIL_INDEX_V(p_idx, nodes.size(), StringName());
|
ERR_FAIL_INDEX_V(p_idx, nodes.size(), StringName());
|
||||||
ERR_FAIL_INDEX_V(p_prop, nodes[p_idx].properties.size(), StringName());
|
ERR_FAIL_INDEX_V(p_prop, nodes[p_idx].properties.size(), StringName());
|
||||||
return names[nodes[p_idx].properties[p_prop].name];
|
return names[nodes[p_idx].properties[p_prop].name & FLAG_PROP_NAME_MASK];
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<String> SceneState::get_node_deferred_nodepath_properties(int p_idx) const {
|
||||||
|
Vector<String> ret;
|
||||||
|
ERR_FAIL_INDEX_V(p_idx, nodes.size(), ret);
|
||||||
|
for (int i = 0; i < nodes[p_idx].properties.size(); i++) {
|
||||||
|
uint32_t idx = nodes[p_idx].properties[i].name;
|
||||||
|
if (idx & FLAG_PATH_PROPERTY_IS_NODE) {
|
||||||
|
ret.push_back(names[idx & FLAG_PROP_NAME_MASK]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Variant SceneState::get_node_property_value(int p_idx, int p_prop) const {
|
Variant SceneState::get_node_property_value(int p_idx, int p_prop) const {
|
||||||
|
@ -1555,13 +1608,16 @@ int SceneState::add_node(int p_parent, int p_owner, int p_type, int p_name, int
|
||||||
return nodes.size() - 1;
|
return nodes.size() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneState::add_node_property(int p_node, int p_name, int p_value) {
|
void SceneState::add_node_property(int p_node, int p_name, int p_value, bool p_deferred_node_path) {
|
||||||
ERR_FAIL_INDEX(p_node, nodes.size());
|
ERR_FAIL_INDEX(p_node, nodes.size());
|
||||||
ERR_FAIL_INDEX(p_name, names.size());
|
ERR_FAIL_INDEX(p_name, names.size());
|
||||||
ERR_FAIL_INDEX(p_value, variants.size());
|
ERR_FAIL_INDEX(p_value, variants.size());
|
||||||
|
|
||||||
NodeData::Property prop;
|
NodeData::Property prop;
|
||||||
prop.name = p_name;
|
prop.name = p_name;
|
||||||
|
if (p_deferred_node_path) {
|
||||||
|
prop.name |= FLAG_PATH_PROPERTY_IS_NODE;
|
||||||
|
}
|
||||||
prop.value = p_value;
|
prop.value = p_value;
|
||||||
nodes.write[p_node].properties.push_back(prop);
|
nodes.write[p_node].properties.push_back(prop);
|
||||||
}
|
}
|
||||||
|
@ -1599,6 +1655,10 @@ void SceneState::add_editable_instance(const NodePath &p_path) {
|
||||||
editable_instances.push_back(p_path);
|
editable_instances.push_back(p_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String SceneState::get_meta_pointer_property(const String &p_property) {
|
||||||
|
return META_POINTER_PROPERTY_BASE + p_property;
|
||||||
|
}
|
||||||
|
|
||||||
Vector<String> SceneState::_get_node_groups(int p_idx) const {
|
Vector<String> SceneState::_get_node_groups(int p_idx) const {
|
||||||
Vector<StringName> groups = get_node_groups(p_idx);
|
Vector<StringName> groups = get_node_groups(p_idx);
|
||||||
Vector<String> ret;
|
Vector<String> ret;
|
||||||
|
|
|
@ -69,6 +69,12 @@ class SceneState : public RefCounted {
|
||||||
Vector<int> groups;
|
Vector<int> groups;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct DeferredNodePathProperties {
|
||||||
|
Node *base = nullptr;
|
||||||
|
StringName property;
|
||||||
|
NodePath path;
|
||||||
|
};
|
||||||
|
|
||||||
Vector<NodeData> nodes;
|
Vector<NodeData> nodes;
|
||||||
|
|
||||||
struct ConnectionData {
|
struct ConnectionData {
|
||||||
|
@ -104,6 +110,8 @@ public:
|
||||||
FLAG_ID_IS_PATH = (1 << 30),
|
FLAG_ID_IS_PATH = (1 << 30),
|
||||||
TYPE_INSTANCED = 0x7FFFFFFF,
|
TYPE_INSTANCED = 0x7FFFFFFF,
|
||||||
FLAG_INSTANCE_IS_PLACEHOLDER = (1 << 30),
|
FLAG_INSTANCE_IS_PLACEHOLDER = (1 << 30),
|
||||||
|
FLAG_PATH_PROPERTY_IS_NODE = (1 << 30),
|
||||||
|
FLAG_PROP_NAME_MASK = FLAG_PATH_PROPERTY_IS_NODE - 1,
|
||||||
FLAG_MASK = (1 << 24) - 1,
|
FLAG_MASK = (1 << 24) - 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -157,6 +165,7 @@ public:
|
||||||
int get_node_property_count(int p_idx) const;
|
int get_node_property_count(int p_idx) const;
|
||||||
StringName get_node_property_name(int p_idx, int p_prop) const;
|
StringName get_node_property_name(int p_idx, int p_prop) const;
|
||||||
Variant get_node_property_value(int p_idx, int p_prop) const;
|
Variant get_node_property_value(int p_idx, int p_prop) const;
|
||||||
|
Vector<String> get_node_deferred_nodepath_properties(int p_idx) const;
|
||||||
|
|
||||||
int get_connection_count() const;
|
int get_connection_count() const;
|
||||||
NodePath get_connection_source(int p_idx) const;
|
NodePath get_connection_source(int p_idx) const;
|
||||||
|
@ -177,7 +186,7 @@ public:
|
||||||
int add_value(const Variant &p_value);
|
int add_value(const Variant &p_value);
|
||||||
int add_node_path(const NodePath &p_path);
|
int add_node_path(const NodePath &p_path);
|
||||||
int add_node(int p_parent, int p_owner, int p_type, int p_name, int p_instance, int p_index);
|
int add_node(int p_parent, int p_owner, int p_type, int p_name, int p_instance, int p_index);
|
||||||
void add_node_property(int p_node, int p_name, int p_value);
|
void add_node_property(int p_node, int p_name, int p_value, bool p_deferred_node_path = false);
|
||||||
void add_node_group(int p_node, int p_group);
|
void add_node_group(int p_node, int p_group);
|
||||||
void set_base_scene(int p_idx);
|
void set_base_scene(int p_idx);
|
||||||
void add_connection(int p_from, int p_to, int p_signal, int p_method, int p_flags, int p_unbinds, const Vector<int> &p_binds);
|
void add_connection(int p_from, int p_to, int p_signal, int p_method, int p_flags, int p_unbinds, const Vector<int> &p_binds);
|
||||||
|
@ -186,6 +195,9 @@ public:
|
||||||
virtual void set_last_modified_time(uint64_t p_time) { last_modified_time = p_time; }
|
virtual void set_last_modified_time(uint64_t p_time) { last_modified_time = p_time; }
|
||||||
uint64_t get_last_modified_time() const { return last_modified_time; }
|
uint64_t get_last_modified_time() const { return last_modified_time; }
|
||||||
|
|
||||||
|
// Used when saving pointers (saves a path property instead).
|
||||||
|
static String get_meta_pointer_property(const String &p_property);
|
||||||
|
|
||||||
SceneState();
|
SceneState();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -212,6 +212,15 @@ Ref<PackedScene> ResourceLoaderText::_parse_node_tag(VariantParser::ResourcePars
|
||||||
type = SceneState::TYPE_INSTANCED; //no type? assume this was instantiated
|
type = SceneState::TYPE_INSTANCED; //no type? assume this was instantiated
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HashSet<StringName> path_properties;
|
||||||
|
|
||||||
|
if (next_tag.fields.has("node_paths")) {
|
||||||
|
Vector<String> paths = next_tag.fields["node_paths"];
|
||||||
|
for (int i = 0; i < paths.size(); i++) {
|
||||||
|
path_properties.insert(paths[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (next_tag.fields.has("instance")) {
|
if (next_tag.fields.has("instance")) {
|
||||||
instance = packed_scene->get_state()->add_value(next_tag.fields["instance"]);
|
instance = packed_scene->get_state()->add_value(next_tag.fields["instance"]);
|
||||||
|
|
||||||
|
@ -276,9 +285,10 @@ Ref<PackedScene> ResourceLoaderText::_parse_node_tag(VariantParser::ResourcePars
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!assign.is_empty()) {
|
if (!assign.is_empty()) {
|
||||||
int nameidx = packed_scene->get_state()->add_name(assign);
|
StringName assign_name = assign;
|
||||||
|
int nameidx = packed_scene->get_state()->add_name(assign_name);
|
||||||
int valueidx = packed_scene->get_state()->add_value(value);
|
int valueidx = packed_scene->get_state()->add_value(value);
|
||||||
packed_scene->get_state()->add_node_property(node_id, nameidx, valueidx);
|
packed_scene->get_state()->add_node_property(node_id, nameidx, valueidx, path_properties.has(assign_name));
|
||||||
//it's assignment
|
//it's assignment
|
||||||
} else if (!next_tag.name.is_empty()) {
|
} else if (!next_tag.name.is_empty()) {
|
||||||
break;
|
break;
|
||||||
|
@ -1939,6 +1949,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Reso
|
||||||
Ref<PackedScene> instance = state->get_node_instance(i);
|
Ref<PackedScene> instance = state->get_node_instance(i);
|
||||||
String instance_placeholder = state->get_node_instance_placeholder(i);
|
String instance_placeholder = state->get_node_instance_placeholder(i);
|
||||||
Vector<StringName> groups = state->get_node_groups(i);
|
Vector<StringName> groups = state->get_node_groups(i);
|
||||||
|
Vector<String> deferred_node_paths = state->get_node_deferred_nodepath_properties(i);
|
||||||
|
|
||||||
String header = "[node";
|
String header = "[node";
|
||||||
header += " name=\"" + String(name).c_escape() + "\"";
|
header += " name=\"" + String(name).c_escape() + "\"";
|
||||||
|
@ -1955,6 +1966,10 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Reso
|
||||||
header += " index=\"" + itos(index) + "\"";
|
header += " index=\"" + itos(index) + "\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (deferred_node_paths.size()) {
|
||||||
|
header += " node_paths=" + Variant(deferred_node_paths).get_construct_string();
|
||||||
|
}
|
||||||
|
|
||||||
if (groups.size()) {
|
if (groups.size()) {
|
||||||
// Write all groups on the same line as they're part of a section header.
|
// Write all groups on the same line as they're part of a section header.
|
||||||
// This improves readability while not impacting VCS friendliness too much,
|
// This improves readability while not impacting VCS friendliness too much,
|
||||||
|
|
Loading…
Reference in a new issue