Merge pull request #60527 from KoBeWi/unique_names_demastered
This commit is contained in:
commit
6ee64331db
11 changed files with 171 additions and 1 deletions
|
@ -35,6 +35,8 @@
|
||||||
#include "core/safe_refcount.h"
|
#include "core/safe_refcount.h"
|
||||||
#include "core/ustring.h"
|
#include "core/ustring.h"
|
||||||
|
|
||||||
|
#define UNIQUE_NODE_PREFIX "%"
|
||||||
|
|
||||||
struct StaticCString {
|
struct StaticCString {
|
||||||
const char *ptr;
|
const char *ptr;
|
||||||
static StaticCString create(const char *p_ptr);
|
static StaticCString create(const char *p_ptr);
|
||||||
|
@ -92,6 +94,17 @@ public:
|
||||||
bool operator==(const String &p_name) const;
|
bool operator==(const String &p_name) const;
|
||||||
bool operator==(const char *p_name) const;
|
bool operator==(const char *p_name) const;
|
||||||
bool operator!=(const String &p_name) const;
|
bool operator!=(const String &p_name) const;
|
||||||
|
|
||||||
|
_FORCE_INLINE_ bool is_node_unique_name() const {
|
||||||
|
if (!_data) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (_data->cname != nullptr) {
|
||||||
|
return (char32_t)_data->cname[0] == (char32_t)UNIQUE_NODE_PREFIX[0];
|
||||||
|
} else {
|
||||||
|
return (char32_t)_data->name[0] == (char32_t)UNIQUE_NODE_PREFIX[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
_FORCE_INLINE_ bool operator<(const StringName &p_name) const {
|
_FORCE_INLINE_ bool operator<(const StringName &p_name) const {
|
||||||
return _data < p_name._data;
|
return _data < p_name._data;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#include "core/math/math_funcs.h"
|
#include "core/math/math_funcs.h"
|
||||||
#include "core/os/memory.h"
|
#include "core/os/memory.h"
|
||||||
#include "core/print_string.h"
|
#include "core/print_string.h"
|
||||||
|
#include "core/string_name.h"
|
||||||
#include "core/translation.h"
|
#include "core/translation.h"
|
||||||
#include "core/ucaps.h"
|
#include "core/ucaps.h"
|
||||||
#include "core/variant.h"
|
#include "core/variant.h"
|
||||||
|
@ -4140,7 +4141,8 @@ String String::property_name_encode() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Changes made to the set of invalid characters must also be reflected in the String documentation.
|
// Changes made to the set of invalid characters must also be reflected in the String documentation.
|
||||||
const String String::invalid_node_name_characters = ". : @ / \"";
|
const String String::invalid_node_name_characters = ". : @ / \" " UNIQUE_NODE_PREFIX;
|
||||||
|
;
|
||||||
|
|
||||||
String String::validate_node_name() const {
|
String String::validate_node_name() const {
|
||||||
Vector<String> chars = String::invalid_node_name_characters.split(" ");
|
Vector<String> chars = String::invalid_node_name_characters.split(" ");
|
||||||
|
|
|
@ -758,6 +758,10 @@
|
||||||
<member name="process_priority" type="int" setter="set_process_priority" getter="get_process_priority" default="0">
|
<member name="process_priority" type="int" setter="set_process_priority" getter="get_process_priority" default="0">
|
||||||
The node's priority in the execution order of the enabled processing callbacks (i.e. [constant NOTIFICATION_PROCESS], [constant NOTIFICATION_PHYSICS_PROCESS] and their internal counterparts). Nodes whose process priority value is [i]lower[/i] will have their processing callbacks executed first.
|
The node's priority in the execution order of the enabled processing callbacks (i.e. [constant NOTIFICATION_PROCESS], [constant NOTIFICATION_PHYSICS_PROCESS] and their internal counterparts). Nodes whose process priority value is [i]lower[/i] will have their processing callbacks executed first.
|
||||||
</member>
|
</member>
|
||||||
|
<member name="unique_name_in_owner" type="bool" setter="set_unique_name_in_owner" getter="is_unique_name_in_owner" default="false">
|
||||||
|
Sets this node's name as a unique name in its [member owner]. This allows the node to be accessed as [code]%Name[/code] instead of the full path, from any node within that scene.
|
||||||
|
If another node with the same owner already had that name declared as unique, that other node's name will no longer be set as having a unique name.
|
||||||
|
</member>
|
||||||
</members>
|
</members>
|
||||||
<signals>
|
<signals>
|
||||||
<signal name="child_entered_tree">
|
<signal name="child_entered_tree">
|
||||||
|
|
1
editor/icons/icon_scene_unique_name.svg
Normal file
1
editor/icons/icon_scene_unique_name.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M4.378 2.224q1.235 0 2.084.866.865.85.865 2.083 0 1.17-.881 2.036-.866.85-2.068.85-1.218 0-2.083-.85-.866-.866-.866-2.068t.866-2.051q.865-.866 2.083-.866zm.962 1.988q-.4-.4-.962-.4-.56 0-.961.4-.401.384-.401.93 0 .56.4.961.401.385.962.385.561 0 .962-.385.4-.4.4-.946 0-.56-.4-.945zm5.45-2.116h1.218L5.677 13.78H4.442Zm1.17 5.722q1.234 0 2.083.866.866.849.866 2.1 0 1.17-.882 2.035-.865.85-2.068.85-1.218 0-2.083-.85-.866-.866-.866-2.084 0-1.202.866-2.051.865-.866 2.083-.866zm.961 1.987q-.4-.4-.962-.4-.56 0-.961.4-.4.385-.4.946 0 .561.4.962.4.384.961.384.561 0 .962-.384.4-.4.4-.946 0-.56-.4-.962z" aria-label="%" style="font-weight:600;font-size:16.0277px;font-family:FreeSans;-inkscape-font-specification:'FreeSans Semi-Bold';letter-spacing:0;word-spacing:0;fill:#e0e0e0;fill-opacity:.996078;stroke-width:.400692"/></svg>
|
After Width: | Height: | Size: 897 B |
|
@ -1122,6 +1122,28 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
case TOOL_TOGGLE_SCENE_UNIQUE_NAME: {
|
||||||
|
List<Node *> selection = editor_selection->get_selected_node_list();
|
||||||
|
List<Node *>::Element *e = selection.front();
|
||||||
|
if (e) {
|
||||||
|
UndoRedo *undo_redo = &editor_data->get_undo_redo();
|
||||||
|
Node *node = e->get();
|
||||||
|
bool enabled = node->is_unique_name_in_owner();
|
||||||
|
if (!enabled && get_tree()->get_edited_scene_root()->get_node_or_null(UNIQUE_NODE_PREFIX + String(node->get_name())) != nullptr) {
|
||||||
|
accept->set_text(TTR("Another node already uses this unique name in the scene."));
|
||||||
|
accept->popup_centered();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!enabled) {
|
||||||
|
undo_redo->create_action(TTR("Enable Scene Unique Name"));
|
||||||
|
} else {
|
||||||
|
undo_redo->create_action(TTR("Disable Scene Unique Name"));
|
||||||
|
}
|
||||||
|
undo_redo->add_do_method(node, "set_unique_name_in_owner", !enabled);
|
||||||
|
undo_redo->add_undo_method(node, "set_unique_name_in_owner", enabled);
|
||||||
|
undo_redo->commit_action();
|
||||||
|
}
|
||||||
|
} break;
|
||||||
case TOOL_CREATE_2D_SCENE:
|
case TOOL_CREATE_2D_SCENE:
|
||||||
case TOOL_CREATE_3D_SCENE:
|
case TOOL_CREATE_3D_SCENE:
|
||||||
case TOOL_CREATE_USER_INTERFACE:
|
case TOOL_CREATE_USER_INTERFACE:
|
||||||
|
@ -1353,8 +1375,17 @@ void SceneTreeDock::_node_replace_owner(Node *p_base, Node *p_node, Node *p_root
|
||||||
UndoRedo *undo_redo = &editor_data->get_undo_redo();
|
UndoRedo *undo_redo = &editor_data->get_undo_redo();
|
||||||
switch (p_mode) {
|
switch (p_mode) {
|
||||||
case MODE_BIDI: {
|
case MODE_BIDI: {
|
||||||
|
bool is_unique = p_node->is_unique_name_in_owner() && p_base->get_node_or_null(UNIQUE_NODE_PREFIX + String(p_node->get_name())) != nullptr;
|
||||||
|
if (is_unique) {
|
||||||
|
// Will create a unique name conflict. Disable before setting owner.
|
||||||
|
undo_redo->add_do_method(p_node, "set_unique_name_in_owner", false);
|
||||||
|
}
|
||||||
undo_redo->add_do_method(p_node, "set_owner", p_root);
|
undo_redo->add_do_method(p_node, "set_owner", p_root);
|
||||||
undo_redo->add_undo_method(p_node, "set_owner", p_base);
|
undo_redo->add_undo_method(p_node, "set_owner", p_base);
|
||||||
|
if (is_unique) {
|
||||||
|
// Will create a unique name conflict. Enable after setting owner.
|
||||||
|
undo_redo->add_undo_method(p_node, "set_unique_name_in_owner", true);
|
||||||
|
}
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case MODE_DO: {
|
case MODE_DO: {
|
||||||
|
@ -2753,6 +2784,12 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
|
||||||
menu->add_icon_shortcut(get_icon("ScriptExtend", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/extend_script"), TOOL_EXTEND_SCRIPT);
|
menu->add_icon_shortcut(get_icon("ScriptExtend", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/extend_script"), TOOL_EXTEND_SCRIPT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (selection[0]->get_owner() == EditorNode::get_singleton()->get_edited_scene()) {
|
||||||
|
// Only for nodes owned by the edited scene root.
|
||||||
|
menu->add_separator();
|
||||||
|
menu->add_icon_check_item(get_icon("SceneUniqueName", "EditorIcons"), TTR("Access as Scene Unique Name"), TOOL_TOGGLE_SCENE_UNIQUE_NAME);
|
||||||
|
menu->set_item_checked(menu->get_item_index(TOOL_TOGGLE_SCENE_UNIQUE_NAME), selection[0]->is_unique_name_in_owner());
|
||||||
|
}
|
||||||
if (existing_script.is_valid() && exisiting_script_removable) {
|
if (existing_script.is_valid() && exisiting_script_removable) {
|
||||||
add_separator = true;
|
add_separator = true;
|
||||||
menu->add_icon_shortcut(get_icon("ScriptRemove", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/detach_script"), TOOL_DETACH_SCRIPT);
|
menu->add_icon_shortcut(get_icon("ScriptRemove", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/detach_script"), TOOL_DETACH_SCRIPT);
|
||||||
|
|
|
@ -92,6 +92,7 @@ class SceneTreeDock : public VBoxContainer {
|
||||||
TOOL_SCENE_CLEAR_INHERITANCE,
|
TOOL_SCENE_CLEAR_INHERITANCE,
|
||||||
TOOL_SCENE_CLEAR_INHERITANCE_CONFIRM,
|
TOOL_SCENE_CLEAR_INHERITANCE_CONFIRM,
|
||||||
TOOL_SCENE_OPEN_INHERITED,
|
TOOL_SCENE_OPEN_INHERITED,
|
||||||
|
TOOL_TOGGLE_SCENE_UNIQUE_NAME,
|
||||||
|
|
||||||
TOOL_CREATE_2D_SCENE,
|
TOOL_CREATE_2D_SCENE,
|
||||||
TOOL_CREATE_3D_SCENE,
|
TOOL_CREATE_3D_SCENE,
|
||||||
|
|
|
@ -145,6 +145,13 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i
|
||||||
|
|
||||||
NodeDock::singleton->get_parent()->call("set_current_tab", NodeDock::singleton->get_index());
|
NodeDock::singleton->get_parent()->call("set_current_tab", NodeDock::singleton->get_index());
|
||||||
NodeDock::singleton->show_groups();
|
NodeDock::singleton->show_groups();
|
||||||
|
} else if (p_id == BUTTON_UNIQUE) {
|
||||||
|
undo_redo->create_action(TTR("Disable Scene Unique Name"));
|
||||||
|
undo_redo->add_do_method(n, "set_unique_name_in_owner", false);
|
||||||
|
undo_redo->add_undo_method(n, "set_unique_name_in_owner", true);
|
||||||
|
undo_redo->add_do_method(this, "_update_tree");
|
||||||
|
undo_redo->add_undo_method(this, "_update_tree");
|
||||||
|
undo_redo->commit_action();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void SceneTreeEditor::_toggle_visible(Node *p_node) {
|
void SceneTreeEditor::_toggle_visible(Node *p_node) {
|
||||||
|
@ -263,6 +270,10 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent, bool p_scroll
|
||||||
item->add_button(0, get_icon("NodeWarning", "EditorIcons"), BUTTON_WARNING, false, TTR("Node configuration warning:") + "\n" + p_node->get_configuration_warning());
|
item->add_button(0, get_icon("NodeWarning", "EditorIcons"), BUTTON_WARNING, false, TTR("Node configuration warning:") + "\n" + p_node->get_configuration_warning());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (p_node->is_unique_name_in_owner()) {
|
||||||
|
item->add_button(0, get_icon("SceneUniqueName", "EditorIcons"), BUTTON_UNIQUE, false, vformat(TTR("This node can be accessed from within anywhere in the scene by preceding it with the '%s' prefix in a node path.\nClick to disable this."), UNIQUE_NODE_PREFIX));
|
||||||
|
}
|
||||||
|
|
||||||
int num_connections = p_node->get_persistent_signal_connection_count();
|
int num_connections = p_node->get_persistent_signal_connection_count();
|
||||||
int num_groups = p_node->get_persistent_group_count();
|
int num_groups = p_node->get_persistent_group_count();
|
||||||
|
|
||||||
|
@ -823,6 +834,13 @@ void SceneTreeEditor::_renamed() {
|
||||||
// Trim leading/trailing whitespace to prevent node names from containing accidental whitespace, which would make it more difficult to get the node via `get_node()`.
|
// Trim leading/trailing whitespace to prevent node names from containing accidental whitespace, which would make it more difficult to get the node via `get_node()`.
|
||||||
new_name = new_name.strip_edges();
|
new_name = new_name.strip_edges();
|
||||||
|
|
||||||
|
if (n->is_unique_name_in_owner() && get_tree()->get_edited_scene_root()->get_node_or_null("%" + new_name) != nullptr) {
|
||||||
|
error->set_text(TTR("Another node already uses this unique name in the scene."));
|
||||||
|
error->popup_centered();
|
||||||
|
which->set_text(0, n->get_name());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!undo_redo) {
|
if (!undo_redo) {
|
||||||
n->set_name(new_name);
|
n->set_name(new_name);
|
||||||
which->set_metadata(0, n->get_path());
|
which->set_metadata(0, n->get_path());
|
||||||
|
|
|
@ -53,6 +53,7 @@ class SceneTreeEditor : public Control {
|
||||||
BUTTON_SIGNALS = 6,
|
BUTTON_SIGNALS = 6,
|
||||||
BUTTON_GROUPS = 7,
|
BUTTON_GROUPS = 7,
|
||||||
BUTTON_PIN = 8,
|
BUTTON_PIN = 8,
|
||||||
|
BUTTON_UNIQUE = 9,
|
||||||
};
|
};
|
||||||
|
|
||||||
Tree *tree;
|
Tree *tree;
|
||||||
|
|
|
@ -269,6 +269,9 @@ void Node::_propagate_after_exit_branch(bool p_exiting_tree) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!found) {
|
if (!found) {
|
||||||
|
if (data.unique_name_in_owner) {
|
||||||
|
_release_unique_name_in_owner();
|
||||||
|
}
|
||||||
data.owner->data.owned.erase(data.OW);
|
data.owner->data.owned.erase(data.OW);
|
||||||
data.owner = nullptr;
|
data.owner = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -979,12 +982,20 @@ void Node::set_name(const String &p_name) {
|
||||||
String name = p_name.validate_node_name();
|
String name = p_name.validate_node_name();
|
||||||
|
|
||||||
ERR_FAIL_COND(name == "");
|
ERR_FAIL_COND(name == "");
|
||||||
|
|
||||||
|
if (data.unique_name_in_owner && data.owner) {
|
||||||
|
_release_unique_name_in_owner();
|
||||||
|
}
|
||||||
data.name = name;
|
data.name = name;
|
||||||
|
|
||||||
if (data.parent) {
|
if (data.parent) {
|
||||||
data.parent->_validate_child_name(this);
|
data.parent->_validate_child_name(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data.unique_name_in_owner && data.owner) {
|
||||||
|
_acquire_unique_name_in_owner();
|
||||||
|
}
|
||||||
|
|
||||||
propagate_notification(NOTIFICATION_PATH_CHANGED);
|
propagate_notification(NOTIFICATION_PATH_CHANGED);
|
||||||
|
|
||||||
if (is_inside_tree()) {
|
if (is_inside_tree()) {
|
||||||
|
@ -1332,6 +1343,24 @@ Node *Node::get_node_or_null(const NodePath &p_path) const {
|
||||||
next = root;
|
next = root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else if (name.is_node_unique_name()) {
|
||||||
|
if (current->data.owned_unique_nodes.size()) {
|
||||||
|
// Has unique nodes in ownership
|
||||||
|
Node **unique = current->data.owned_unique_nodes.getptr(name);
|
||||||
|
if (!unique) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
next = *unique;
|
||||||
|
} else if (current->data.owner) {
|
||||||
|
Node **unique = current->data.owner->data.owned_unique_nodes.getptr(name);
|
||||||
|
if (!unique) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
next = *unique;
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
next = nullptr;
|
next = nullptr;
|
||||||
|
|
||||||
|
@ -1508,8 +1537,54 @@ void Node::_set_owner_nocheck(Node *p_owner) {
|
||||||
data.OW = data.owner->data.owned.back();
|
data.OW = data.owner->data.owned.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Node::_release_unique_name_in_owner() {
|
||||||
|
ERR_FAIL_NULL(data.owner); // Sanity check.
|
||||||
|
StringName key = StringName(UNIQUE_NODE_PREFIX + data.name.operator String());
|
||||||
|
Node **which = data.owner->data.owned_unique_nodes.getptr(key);
|
||||||
|
if (which == nullptr || *which != this) {
|
||||||
|
return; // Ignore.
|
||||||
|
}
|
||||||
|
data.owner->data.owned_unique_nodes.erase(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Node::_acquire_unique_name_in_owner() {
|
||||||
|
ERR_FAIL_NULL(data.owner); // Sanity check.
|
||||||
|
StringName key = StringName(UNIQUE_NODE_PREFIX + data.name.operator String());
|
||||||
|
Node **which = data.owner->data.owned_unique_nodes.getptr(key);
|
||||||
|
if (which != nullptr && *which != this) {
|
||||||
|
WARN_PRINT(vformat(RTR("Setting node name '%s' to be unique within scene for '%s', but it's already claimed by '%s'. This node is no longer set unique."), get_name(), is_inside_tree() ? get_path() : data.owner->get_path_to(this), is_inside_tree() ? (*which)->get_path() : data.owner->get_path_to(*which)));
|
||||||
|
data.unique_name_in_owner = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data.owner->data.owned_unique_nodes[key] = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Node::set_unique_name_in_owner(bool p_enabled) {
|
||||||
|
if (data.unique_name_in_owner == p_enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.unique_name_in_owner && data.owner != nullptr) {
|
||||||
|
_release_unique_name_in_owner();
|
||||||
|
}
|
||||||
|
data.unique_name_in_owner = p_enabled;
|
||||||
|
|
||||||
|
if (data.unique_name_in_owner && data.owner != nullptr) {
|
||||||
|
_acquire_unique_name_in_owner();
|
||||||
|
}
|
||||||
|
|
||||||
|
update_configuration_warning();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Node::is_unique_name_in_owner() const {
|
||||||
|
return data.unique_name_in_owner;
|
||||||
|
}
|
||||||
|
|
||||||
void Node::set_owner(Node *p_owner) {
|
void Node::set_owner(Node *p_owner) {
|
||||||
if (data.owner) {
|
if (data.owner) {
|
||||||
|
if (data.unique_name_in_owner) {
|
||||||
|
_release_unique_name_in_owner();
|
||||||
|
}
|
||||||
data.owner->data.owned.erase(data.OW);
|
data.owner->data.owned.erase(data.OW);
|
||||||
data.OW = nullptr;
|
data.OW = nullptr;
|
||||||
data.owner = nullptr;
|
data.owner = nullptr;
|
||||||
|
@ -1536,6 +1611,10 @@ void Node::set_owner(Node *p_owner) {
|
||||||
ERR_FAIL_COND(!owner_valid);
|
ERR_FAIL_COND(!owner_valid);
|
||||||
|
|
||||||
_set_owner_nocheck(p_owner);
|
_set_owner_nocheck(p_owner);
|
||||||
|
|
||||||
|
if (data.unique_name_in_owner) {
|
||||||
|
_acquire_unique_name_in_owner();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Node *Node::get_owner() const {
|
Node *Node::get_owner() const {
|
||||||
return data.owner;
|
return data.owner;
|
||||||
|
@ -2918,6 +2997,8 @@ void Node::_bind_methods() {
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
ClassDB::bind_method(D_METHOD("_set_property_pinned", "property", "pinned"), &Node::set_property_pinned);
|
ClassDB::bind_method(D_METHOD("_set_property_pinned", "property", "pinned"), &Node::set_property_pinned);
|
||||||
#endif
|
#endif
|
||||||
|
ClassDB::bind_method(D_METHOD("set_unique_name_in_owner", "enable"), &Node::set_unique_name_in_owner);
|
||||||
|
ClassDB::bind_method(D_METHOD("is_unique_name_in_owner"), &Node::is_unique_name_in_owner);
|
||||||
|
|
||||||
{
|
{
|
||||||
MethodInfo mi;
|
MethodInfo mi;
|
||||||
|
@ -3003,6 +3084,7 @@ void Node::_bind_methods() {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "name", PROPERTY_HINT_NONE, "", 0), "set_name", "get_name");
|
ADD_PROPERTY(PropertyInfo(Variant::STRING, "name", PROPERTY_HINT_NONE, "", 0), "set_name", "get_name");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "unique_name_in_owner", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_unique_name_in_owner", "is_unique_name_in_owner");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "filename", PROPERTY_HINT_NONE, "", 0), "set_filename", "get_filename");
|
ADD_PROPERTY(PropertyInfo(Variant::STRING, "filename", PROPERTY_HINT_NONE, "", 0), "set_filename", "get_filename");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "owner", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_owner", "get_owner");
|
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "owner", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_owner", "get_owner");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "multiplayer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", 0), "", "get_multiplayer");
|
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "multiplayer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", 0), "", "get_multiplayer");
|
||||||
|
|
|
@ -97,6 +97,9 @@ private:
|
||||||
Node *parent;
|
Node *parent;
|
||||||
Node *owner;
|
Node *owner;
|
||||||
Vector<Node *> children; // list of children
|
Vector<Node *> children; // list of children
|
||||||
|
HashMap<StringName, Node *> owned_unique_nodes;
|
||||||
|
bool unique_name_in_owner = false;
|
||||||
|
|
||||||
int pos;
|
int pos;
|
||||||
int depth;
|
int depth;
|
||||||
int blocked; // safeguard that throws an error when attempting to modify the tree in a harmful way while being traversed.
|
int blocked; // safeguard that throws an error when attempting to modify the tree in a harmful way while being traversed.
|
||||||
|
@ -203,6 +206,8 @@ private:
|
||||||
friend class SceneTree;
|
friend class SceneTree;
|
||||||
|
|
||||||
void _set_tree(SceneTree *p_tree);
|
void _set_tree(SceneTree *p_tree);
|
||||||
|
void _release_unique_name_in_owner();
|
||||||
|
void _acquire_unique_name_in_owner();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void _block() { data.blocked++; }
|
void _block() { data.blocked++; }
|
||||||
|
@ -326,6 +331,9 @@ public:
|
||||||
Node *get_owner() const;
|
Node *get_owner() const;
|
||||||
void get_owned_by(Node *p_by, List<Node *> *p_owned);
|
void get_owned_by(Node *p_by, List<Node *> *p_owned);
|
||||||
|
|
||||||
|
void set_unique_name_in_owner(bool p_enabled);
|
||||||
|
bool is_unique_name_in_owner() const;
|
||||||
|
|
||||||
void remove_and_skip();
|
void remove_and_skip();
|
||||||
int get_index() const;
|
int get_index() const;
|
||||||
|
|
||||||
|
|
|
@ -309,6 +309,9 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
|
||||||
NODE_FROM_ID(owner, n.owner);
|
NODE_FROM_ID(owner, n.owner);
|
||||||
if (owner) {
|
if (owner) {
|
||||||
node->_set_owner_nocheck(owner);
|
node->_set_owner_nocheck(owner);
|
||||||
|
if (node->data.unique_name_in_owner) {
|
||||||
|
node->_acquire_unique_name_in_owner();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue