|
@@ -166,7 +166,7 @@ void Node::_notification(int p_notification) {
|
|
|
|
|
|
// kill children as cleanly as possible
|
|
|
while (data.children.size()) {
|
|
|
- Node *child = data.children[data.children.size() - 1]; //begin from the end because its faster and more consistent with creation
|
|
|
+ Node *child = data.children.last()->value; // begin from the end because its faster and more consistent with creation
|
|
|
memdelete(child);
|
|
|
}
|
|
|
} break;
|
|
@@ -176,9 +176,10 @@ void Node::_notification(int p_notification) {
|
|
|
void Node::_propagate_ready() {
|
|
|
data.ready_notified = true;
|
|
|
data.blocked++;
|
|
|
- for (int i = 0; i < data.children.size(); i++) {
|
|
|
- data.children[i]->_propagate_ready();
|
|
|
+ for (KeyValue<StringName, Node *> &K : data.children) {
|
|
|
+ K.value->_propagate_ready();
|
|
|
}
|
|
|
+
|
|
|
data.blocked--;
|
|
|
|
|
|
notification(NOTIFICATION_POST_ENTER_TREE);
|
|
@@ -228,9 +229,9 @@ void Node::_propagate_enter_tree() {
|
|
|
data.blocked++;
|
|
|
//block while adding children
|
|
|
|
|
|
- for (int i = 0; i < data.children.size(); i++) {
|
|
|
- if (!data.children[i]->is_inside_tree()) { // could have been added in enter_tree
|
|
|
- data.children[i]->_propagate_enter_tree();
|
|
|
+ for (KeyValue<StringName, Node *> &K : data.children) {
|
|
|
+ if (!K.value->is_inside_tree()) { // could have been added in enter_tree
|
|
|
+ K.value->_propagate_enter_tree();
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -267,9 +268,11 @@ void Node::_propagate_after_exit_tree() {
|
|
|
}
|
|
|
|
|
|
data.blocked++;
|
|
|
- for (int i = data.children.size() - 1; i >= 0; i--) {
|
|
|
- data.children[i]->_propagate_after_exit_tree();
|
|
|
+
|
|
|
+ for (HashMap<StringName, Node *>::Iterator I = data.children.last(); I; --I) {
|
|
|
+ I->value->_propagate_after_exit_tree();
|
|
|
}
|
|
|
+
|
|
|
data.blocked--;
|
|
|
|
|
|
emit_signal(SceneStringNames::get_singleton()->tree_exited);
|
|
@@ -286,8 +289,8 @@ void Node::_propagate_exit_tree() {
|
|
|
#endif
|
|
|
data.blocked++;
|
|
|
|
|
|
- for (int i = data.children.size() - 1; i >= 0; i--) {
|
|
|
- data.children[i]->_propagate_exit_tree();
|
|
|
+ for (HashMap<StringName, Node *>::Iterator I = data.children.last(); I; --I) {
|
|
|
+ I->value->_propagate_exit_tree();
|
|
|
}
|
|
|
|
|
|
data.blocked--;
|
|
@@ -329,25 +332,26 @@ void Node::move_child(Node *p_child, int p_index) {
|
|
|
ERR_FAIL_NULL(p_child);
|
|
|
ERR_FAIL_COND_MSG(p_child->data.parent != this, "Child is not a child of this node.");
|
|
|
|
|
|
+ _update_children_cache();
|
|
|
// We need to check whether node is internal and move it only in the relevant node range.
|
|
|
- if (p_child->_is_internal_front()) {
|
|
|
+ if (p_child->data.internal_mode == INTERNAL_MODE_FRONT) {
|
|
|
if (p_index < 0) {
|
|
|
- p_index += data.internal_children_front;
|
|
|
+ p_index += data.internal_children_front_count_cache;
|
|
|
}
|
|
|
- ERR_FAIL_INDEX_MSG(p_index, data.internal_children_front, vformat("Invalid new child index: %d. Child is internal.", p_index));
|
|
|
+ ERR_FAIL_INDEX_MSG(p_index, data.internal_children_front_count_cache, vformat("Invalid new child index: %d. Child is internal.", p_index));
|
|
|
_move_child(p_child, p_index);
|
|
|
- } else if (p_child->_is_internal_back()) {
|
|
|
+ } else if (p_child->data.internal_mode == INTERNAL_MODE_BACK) {
|
|
|
if (p_index < 0) {
|
|
|
- p_index += data.internal_children_back;
|
|
|
+ p_index += data.internal_children_back_count_cache;
|
|
|
}
|
|
|
- ERR_FAIL_INDEX_MSG(p_index, data.internal_children_back, vformat("Invalid new child index: %d. Child is internal.", p_index));
|
|
|
- _move_child(p_child, data.children.size() - data.internal_children_back + p_index);
|
|
|
+ ERR_FAIL_INDEX_MSG(p_index, data.internal_children_back_count_cache, vformat("Invalid new child index: %d. Child is internal.", p_index));
|
|
|
+ _move_child(p_child, (int)data.children_cache.size() - data.internal_children_back_count_cache + p_index);
|
|
|
} else {
|
|
|
if (p_index < 0) {
|
|
|
p_index += get_child_count(false);
|
|
|
}
|
|
|
- ERR_FAIL_INDEX_MSG(p_index, data.children.size() + 1 - data.internal_children_front - data.internal_children_back, vformat("Invalid new child index: %d.", p_index));
|
|
|
- _move_child(p_child, p_index + data.internal_children_front);
|
|
|
+ ERR_FAIL_INDEX_MSG(p_index, (int)data.children_cache.size() + 1 - data.internal_children_front_count_cache - data.internal_children_back_count_cache, vformat("Invalid new child index: %d.", p_index));
|
|
|
+ _move_child(p_child, p_index + data.internal_children_front_count_cache);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -357,30 +361,32 @@ void Node::_move_child(Node *p_child, int p_index, bool p_ignore_end) {
|
|
|
// Specifying one place beyond the end
|
|
|
// means the same as moving to the last index
|
|
|
if (!p_ignore_end) { // p_ignore_end is a little hack to make back internal children work properly.
|
|
|
- if (p_child->_is_internal_front()) {
|
|
|
- if (p_index == data.internal_children_front) {
|
|
|
+ if (p_child->data.internal_mode == INTERNAL_MODE_FRONT) {
|
|
|
+ if (p_index == data.internal_children_front_count_cache) {
|
|
|
p_index--;
|
|
|
}
|
|
|
- } else if (p_child->_is_internal_back()) {
|
|
|
- if (p_index == data.children.size()) {
|
|
|
+ } else if (p_child->data.internal_mode == INTERNAL_MODE_BACK) {
|
|
|
+ if (p_index == (int)data.children_cache.size()) {
|
|
|
p_index--;
|
|
|
}
|
|
|
} else {
|
|
|
- if (p_index == data.children.size() - data.internal_children_back) {
|
|
|
+ if (p_index == (int)data.children_cache.size() - data.internal_children_back_count_cache) {
|
|
|
p_index--;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (p_child->data.index == p_index) {
|
|
|
+ int child_index = p_child->get_index();
|
|
|
+
|
|
|
+ if (child_index == p_index) {
|
|
|
return; //do nothing
|
|
|
}
|
|
|
|
|
|
- int motion_from = MIN(p_index, p_child->data.index);
|
|
|
- int motion_to = MAX(p_index, p_child->data.index);
|
|
|
+ int motion_from = MIN(p_index, child_index);
|
|
|
+ int motion_to = MAX(p_index, child_index);
|
|
|
|
|
|
- data.children.remove_at(p_child->data.index);
|
|
|
- data.children.insert(p_index, p_child);
|
|
|
+ data.children_cache.remove_at(child_index);
|
|
|
+ data.children_cache.insert(p_index, p_child);
|
|
|
|
|
|
if (data.tree) {
|
|
|
data.tree->tree_changed();
|
|
@@ -389,13 +395,18 @@ void Node::_move_child(Node *p_child, int p_index, bool p_ignore_end) {
|
|
|
data.blocked++;
|
|
|
//new pos first
|
|
|
for (int i = motion_from; i <= motion_to; i++) {
|
|
|
- data.children[i]->data.index = i;
|
|
|
+ if (data.children_cache[i]->data.internal_mode == INTERNAL_MODE_DISABLED) {
|
|
|
+ data.children_cache[i]->data.index = i - data.internal_children_front_count_cache;
|
|
|
+ } else if (data.children_cache[i]->data.internal_mode == INTERNAL_MODE_BACK) {
|
|
|
+ data.children_cache[i]->data.index = i - data.internal_children_front_count_cache - data.external_children_count_cache;
|
|
|
+ } else {
|
|
|
+ data.children_cache[i]->data.index = i;
|
|
|
+ }
|
|
|
}
|
|
|
// notification second
|
|
|
move_child_notify(p_child);
|
|
|
notification(NOTIFICATION_CHILD_ORDER_CHANGED);
|
|
|
emit_signal(SNAME("child_order_changed"));
|
|
|
-
|
|
|
p_child->_propagate_groups_dirty();
|
|
|
|
|
|
data.blocked--;
|
|
@@ -408,8 +419,8 @@ void Node::_propagate_groups_dirty() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- for (int i = 0; i < data.children.size(); i++) {
|
|
|
- data.children[i]->_propagate_groups_dirty();
|
|
|
+ for (KeyValue<StringName, Node *> &K : data.children) {
|
|
|
+ K.value->_propagate_groups_dirty();
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -529,8 +540,8 @@ void Node::_propagate_pause_notification(bool p_enable) {
|
|
|
notification(NOTIFICATION_UNPAUSED);
|
|
|
}
|
|
|
|
|
|
- for (int i = 0; i < data.children.size(); i++) {
|
|
|
- data.children[i]->_propagate_pause_notification(p_enable);
|
|
|
+ for (KeyValue<StringName, Node *> &K : data.children) {
|
|
|
+ K.value->_propagate_pause_notification(p_enable);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -549,8 +560,8 @@ void Node::_propagate_process_owner(Node *p_owner, int p_pause_notification, int
|
|
|
notification(p_enabled_notification);
|
|
|
}
|
|
|
|
|
|
- for (int i = 0; i < data.children.size(); i++) {
|
|
|
- Node *c = data.children[i];
|
|
|
+ for (KeyValue<StringName, Node *> &K : data.children) {
|
|
|
+ Node *c = K.value;
|
|
|
if (c->data.process_mode == PROCESS_MODE_INHERIT) {
|
|
|
c->_propagate_process_owner(p_owner, p_pause_notification, p_enabled_notification);
|
|
|
}
|
|
@@ -561,8 +572,8 @@ void Node::set_multiplayer_authority(int p_peer_id, bool p_recursive) {
|
|
|
data.multiplayer_authority = p_peer_id;
|
|
|
|
|
|
if (p_recursive) {
|
|
|
- for (int i = 0; i < data.children.size(); i++) {
|
|
|
- data.children[i]->set_multiplayer_authority(p_peer_id, true);
|
|
|
+ for (KeyValue<StringName, Node *> &K : data.children) {
|
|
|
+ K.value->set_multiplayer_authority(p_peer_id, true);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -912,10 +923,13 @@ void Node::set_name(const String &p_name) {
|
|
|
if (data.unique_name_in_owner && data.owner) {
|
|
|
_release_unique_name_in_owner();
|
|
|
}
|
|
|
+ String old_name = data.name;
|
|
|
data.name = name;
|
|
|
|
|
|
if (data.parent) {
|
|
|
+ data.parent->data.children.erase(old_name);
|
|
|
data.parent->_validate_child_name(this, true);
|
|
|
+ data.parent->data.children.insert(data.name, this);
|
|
|
}
|
|
|
|
|
|
if (data.unique_name_in_owner && data.owner) {
|
|
@@ -977,19 +991,8 @@ void Node::_validate_child_name(Node *p_child, bool p_force_human_readable) {
|
|
|
//new unique name must be assigned
|
|
|
unique = false;
|
|
|
} else {
|
|
|
- //check if exists
|
|
|
- Node **children = data.children.ptrw();
|
|
|
- int cc = data.children.size();
|
|
|
-
|
|
|
- for (int i = 0; i < cc; i++) {
|
|
|
- if (children[i] == p_child) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (children[i]->data.name == p_child->data.name) {
|
|
|
- unique = false;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
+ const Node *const *existing = data.children.getptr(p_child->data.name);
|
|
|
+ unique = !existing || *existing == p_child;
|
|
|
}
|
|
|
|
|
|
if (!unique) {
|
|
@@ -1053,25 +1056,9 @@ void Node::_generate_serial_child_name(const Node *p_child, StringName &name) co
|
|
|
name = p_child->get_class();
|
|
|
}
|
|
|
|
|
|
- //quickly test if proposed name exists
|
|
|
- int cc = data.children.size(); //children count
|
|
|
- const Node *const *children_ptr = data.children.ptr();
|
|
|
-
|
|
|
- {
|
|
|
- bool exists = false;
|
|
|
-
|
|
|
- for (int i = 0; i < cc; i++) {
|
|
|
- if (children_ptr[i] == p_child) { //exclude self in renaming if it's already a child
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (children_ptr[i]->data.name == name) {
|
|
|
- exists = true;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (!exists) {
|
|
|
- return; //if it does not exist, it does not need validation
|
|
|
- }
|
|
|
+ const Node *const *existing = data.children.getptr(name);
|
|
|
+ if (!existing || *existing == p_child) { // Unused, or is current node.
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
// Extract trailing number
|
|
@@ -1098,16 +1085,9 @@ void Node::_generate_serial_child_name(const Node *p_child, StringName &name) co
|
|
|
|
|
|
for (;;) {
|
|
|
StringName attempt = name_string + nums;
|
|
|
- bool exists = false;
|
|
|
|
|
|
- for (int i = 0; i < cc; i++) {
|
|
|
- if (children_ptr[i] == p_child) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (children_ptr[i]->data.name == attempt) {
|
|
|
- exists = true;
|
|
|
- }
|
|
|
- }
|
|
|
+ existing = data.children.getptr(attempt);
|
|
|
+ bool exists = existing != nullptr && *existing != p_child;
|
|
|
|
|
|
if (!exists) {
|
|
|
name = attempt;
|
|
@@ -1124,17 +1104,34 @@ void Node::_generate_serial_child_name(const Node *p_child, StringName &name) co
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void Node::_add_child_nocheck(Node *p_child, const StringName &p_name) {
|
|
|
+void Node::_add_child_nocheck(Node *p_child, const StringName &p_name, InternalMode p_internal_mode) {
|
|
|
//add a child node quickly, without name validation
|
|
|
|
|
|
p_child->data.name = p_name;
|
|
|
- p_child->data.index = data.children.size();
|
|
|
- data.children.push_back(p_child);
|
|
|
+ data.children.insert(p_name, p_child);
|
|
|
+
|
|
|
+ p_child->data.internal_mode = p_internal_mode;
|
|
|
+ switch (p_internal_mode) {
|
|
|
+ case INTERNAL_MODE_FRONT: {
|
|
|
+ p_child->data.index = data.internal_children_front_count_cache++;
|
|
|
+ } break;
|
|
|
+ case INTERNAL_MODE_BACK: {
|
|
|
+ p_child->data.index = data.internal_children_back_count_cache++;
|
|
|
+ } break;
|
|
|
+ case INTERNAL_MODE_DISABLED: {
|
|
|
+ p_child->data.index = data.external_children_count_cache++;
|
|
|
+ } break;
|
|
|
+ }
|
|
|
+
|
|
|
p_child->data.parent = this;
|
|
|
|
|
|
- if (data.internal_children_back > 0) {
|
|
|
- _move_child(p_child, data.children.size() - data.internal_children_back - 1);
|
|
|
+ if (!data.children_cache_dirty && p_internal_mode == INTERNAL_MODE_DISABLED && data.internal_children_back_count_cache == 0) {
|
|
|
+ // Special case, also add to the cached children array since its cheap.
|
|
|
+ data.children_cache.push_back(p_child);
|
|
|
+ } else {
|
|
|
+ data.children_cache_dirty = true;
|
|
|
}
|
|
|
+
|
|
|
p_child->notification(NOTIFICATION_PARENTED);
|
|
|
|
|
|
if (data.tree) {
|
|
@@ -1159,17 +1156,7 @@ void Node::add_child(Node *p_child, bool p_force_readable_name, InternalMode p_i
|
|
|
ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, `add_child()` failed. Consider using `add_child.call_deferred(child)` instead.");
|
|
|
|
|
|
_validate_child_name(p_child, p_force_readable_name);
|
|
|
- _add_child_nocheck(p_child, p_child->data.name);
|
|
|
-
|
|
|
- if (p_internal == INTERNAL_MODE_FRONT) {
|
|
|
- _move_child(p_child, data.internal_children_front);
|
|
|
- data.internal_children_front++;
|
|
|
- } else if (p_internal == INTERNAL_MODE_BACK) {
|
|
|
- if (data.internal_children_back > 0) {
|
|
|
- _move_child(p_child, data.children.size() - 1, true);
|
|
|
- }
|
|
|
- data.internal_children_back++;
|
|
|
- }
|
|
|
+ _add_child_nocheck(p_child, p_child->data.name, p_internal);
|
|
|
}
|
|
|
|
|
|
void Node::add_sibling(Node *p_sibling, bool p_force_readable_name) {
|
|
@@ -1178,49 +1165,25 @@ void Node::add_sibling(Node *p_sibling, bool p_force_readable_name) {
|
|
|
ERR_FAIL_COND_MSG(p_sibling == this, vformat("Can't add sibling '%s' to itself.", p_sibling->get_name())); // adding to itself!
|
|
|
ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, `add_sibling()` failed. Consider using `add_sibling.call_deferred(sibling)` instead.");
|
|
|
|
|
|
- InternalMode internal = INTERNAL_MODE_DISABLED;
|
|
|
- if (_is_internal_front()) { // The sibling will have the same internal status.
|
|
|
- internal = INTERNAL_MODE_FRONT;
|
|
|
- } else if (_is_internal_back()) {
|
|
|
- internal = INTERNAL_MODE_BACK;
|
|
|
- }
|
|
|
-
|
|
|
- data.parent->add_child(p_sibling, p_force_readable_name, internal);
|
|
|
+ data.parent->add_child(p_sibling, p_force_readable_name, data.internal_mode);
|
|
|
+ data.parent->_update_children_cache();
|
|
|
data.parent->_move_child(p_sibling, get_index() + 1);
|
|
|
}
|
|
|
|
|
|
void Node::remove_child(Node *p_child) {
|
|
|
ERR_FAIL_NULL(p_child);
|
|
|
ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy adding/removing children, `remove_child()` can't be called at this time. Consider using `remove_child.call_deferred(child)` instead.");
|
|
|
-
|
|
|
- int child_count = data.children.size();
|
|
|
- Node **children = data.children.ptrw();
|
|
|
- int idx = -1;
|
|
|
-
|
|
|
- if (p_child->data.index >= 0 && p_child->data.index < child_count) {
|
|
|
- if (children[p_child->data.index] == p_child) {
|
|
|
- idx = p_child->data.index;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (idx == -1) { //maybe removed while unparenting or something and index was not updated, so just in case the above fails, try this.
|
|
|
- for (int i = 0; i < child_count; i++) {
|
|
|
- if (children[i] == p_child) {
|
|
|
- idx = i;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- ERR_FAIL_COND_MSG(idx == -1, vformat("Cannot remove child node '%s' as it is not a child of this node.", p_child->get_name()));
|
|
|
- //ERR_FAIL_COND( p_child->data.blocked > 0 );
|
|
|
-
|
|
|
- // If internal child, update the counter.
|
|
|
- if (p_child->_is_internal_front()) {
|
|
|
- data.internal_children_front--;
|
|
|
- } else if (p_child->_is_internal_back()) {
|
|
|
- data.internal_children_back--;
|
|
|
- }
|
|
|
+ ERR_FAIL_COND(p_child->data.parent != this);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Do not change the data.internal_children*cache counters here.
|
|
|
+ * Because if nodes are re-added, the indices can remain
|
|
|
+ * greater-than-everything indices and children added remain
|
|
|
+ * properly ordered.
|
|
|
+ *
|
|
|
+ * All children indices and counters will be updated next time the
|
|
|
+ * cache is re-generated.
|
|
|
+ */
|
|
|
|
|
|
data.blocked++;
|
|
|
p_child->_set_tree(nullptr);
|
|
@@ -1228,17 +1191,12 @@ void Node::remove_child(Node *p_child) {
|
|
|
|
|
|
remove_child_notify(p_child);
|
|
|
p_child->notification(NOTIFICATION_UNPARENTED);
|
|
|
- data.blocked--;
|
|
|
-
|
|
|
- data.children.remove_at(idx);
|
|
|
|
|
|
- //update pointer and size
|
|
|
- child_count = data.children.size();
|
|
|
- children = data.children.ptrw();
|
|
|
+ data.blocked--;
|
|
|
|
|
|
- for (int i = idx; i < child_count; i++) {
|
|
|
- children[i]->data.index = i;
|
|
|
- }
|
|
|
+ data.children_cache_dirty = true;
|
|
|
+ bool success = data.children.erase(p_child->data.name);
|
|
|
+ ERR_FAIL_COND_MSG(!success, "Children name does not match parent name in hashtable, this is a bug.");
|
|
|
|
|
|
notification(NOTIFICATION_CHILD_ORDER_CHANGED);
|
|
|
emit_signal(SNAME("child_order_changed"));
|
|
@@ -1251,42 +1209,73 @@ void Node::remove_child(Node *p_child) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+void Node::_update_children_cache_impl() const {
|
|
|
+ // Assign children
|
|
|
+ data.children_cache.resize(data.children.size());
|
|
|
+ int idx = 0;
|
|
|
+ for (const KeyValue<StringName, Node *> &K : data.children) {
|
|
|
+ data.children_cache[idx] = K.value;
|
|
|
+ idx++;
|
|
|
+ }
|
|
|
+ // Sort them
|
|
|
+ data.children_cache.sort_custom<ComparatorByIndex>();
|
|
|
+ // Update indices
|
|
|
+ data.external_children_count_cache = 0;
|
|
|
+ data.internal_children_back_count_cache = 0;
|
|
|
+ data.internal_children_front_count_cache = 0;
|
|
|
+
|
|
|
+ for (uint32_t i = 0; i < data.children_cache.size(); i++) {
|
|
|
+ switch (data.children_cache[i]->data.internal_mode) {
|
|
|
+ case INTERNAL_MODE_DISABLED: {
|
|
|
+ data.children_cache[i]->data.index = data.external_children_count_cache++;
|
|
|
+ } break;
|
|
|
+ case INTERNAL_MODE_FRONT: {
|
|
|
+ data.children_cache[i]->data.index = data.internal_children_front_count_cache++;
|
|
|
+ } break;
|
|
|
+ case INTERNAL_MODE_BACK: {
|
|
|
+ data.children_cache[i]->data.index = data.internal_children_back_count_cache++;
|
|
|
+ } break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ data.children_cache_dirty = false;
|
|
|
+}
|
|
|
+
|
|
|
int Node::get_child_count(bool p_include_internal) const {
|
|
|
+ _update_children_cache();
|
|
|
+
|
|
|
if (p_include_internal) {
|
|
|
- return data.children.size();
|
|
|
+ return data.children_cache.size();
|
|
|
} else {
|
|
|
- return data.children.size() - data.internal_children_front - data.internal_children_back;
|
|
|
+ return data.children_cache.size() - data.internal_children_front_count_cache - data.internal_children_back_count_cache;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
Node *Node::get_child(int p_index, bool p_include_internal) const {
|
|
|
+ _update_children_cache();
|
|
|
+
|
|
|
if (p_include_internal) {
|
|
|
if (p_index < 0) {
|
|
|
- p_index += data.children.size();
|
|
|
+ p_index += data.children_cache.size();
|
|
|
}
|
|
|
- ERR_FAIL_INDEX_V(p_index, data.children.size(), nullptr);
|
|
|
- return data.children[p_index];
|
|
|
+ ERR_FAIL_INDEX_V(p_index, (int)data.children_cache.size(), nullptr);
|
|
|
+ return data.children_cache[p_index];
|
|
|
} else {
|
|
|
if (p_index < 0) {
|
|
|
- p_index += data.children.size() - data.internal_children_front - data.internal_children_back;
|
|
|
+ p_index += (int)data.children_cache.size() - data.internal_children_front_count_cache - data.internal_children_back_count_cache;
|
|
|
}
|
|
|
- ERR_FAIL_INDEX_V(p_index, data.children.size() - data.internal_children_front - data.internal_children_back, nullptr);
|
|
|
- p_index += data.internal_children_front;
|
|
|
- return data.children[p_index];
|
|
|
+ ERR_FAIL_INDEX_V(p_index, (int)data.children_cache.size() - data.internal_children_front_count_cache - data.internal_children_back_count_cache, nullptr);
|
|
|
+ p_index += data.internal_children_front_count_cache;
|
|
|
+ return data.children_cache[p_index];
|
|
|
}
|
|
|
}
|
|
|
|
|
|
Node *Node::_get_child_by_name(const StringName &p_name) const {
|
|
|
- int cc = data.children.size();
|
|
|
- Node *const *cd = data.children.ptr();
|
|
|
-
|
|
|
- for (int i = 0; i < cc; i++) {
|
|
|
- if (cd[i]->data.name == p_name) {
|
|
|
- return cd[i];
|
|
|
- }
|
|
|
+ const Node *const *node = data.children.getptr(p_name);
|
|
|
+ if (node) {
|
|
|
+ return const_cast<Node *>(*node);
|
|
|
+ } else {
|
|
|
+ return nullptr;
|
|
|
}
|
|
|
-
|
|
|
- return nullptr;
|
|
|
}
|
|
|
|
|
|
Node *Node::get_node_or_null(const NodePath &p_path) const {
|
|
@@ -1348,18 +1337,12 @@ Node *Node::get_node_or_null(const NodePath &p_path) const {
|
|
|
|
|
|
} else {
|
|
|
next = nullptr;
|
|
|
-
|
|
|
- for (int j = 0; j < current->data.children.size(); j++) {
|
|
|
- Node *child = current->data.children[j];
|
|
|
-
|
|
|
- if (child->data.name == name) {
|
|
|
- next = child;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- if (next == nullptr) {
|
|
|
+ const Node *const *node = current->data.children.getptr(name);
|
|
|
+ if (node) {
|
|
|
+ next = const_cast<Node *>(*node);
|
|
|
+ } else {
|
|
|
return nullptr;
|
|
|
- };
|
|
|
+ }
|
|
|
}
|
|
|
current = next;
|
|
|
}
|
|
@@ -1402,9 +1385,9 @@ bool Node::has_node(const NodePath &p_path) const {
|
|
|
// Can be recursive or not, and limited to owned nodes.
|
|
|
Node *Node::find_child(const String &p_pattern, bool p_recursive, bool p_owned) const {
|
|
|
ERR_FAIL_COND_V(p_pattern.is_empty(), nullptr);
|
|
|
-
|
|
|
- Node *const *cptr = data.children.ptr();
|
|
|
- int ccount = data.children.size();
|
|
|
+ _update_children_cache();
|
|
|
+ Node *const *cptr = data.children_cache.ptr();
|
|
|
+ int ccount = data.children_cache.size();
|
|
|
for (int i = 0; i < ccount; i++) {
|
|
|
if (p_owned && !cptr[i]->data.owner) {
|
|
|
continue;
|
|
@@ -1431,9 +1414,9 @@ Node *Node::find_child(const String &p_pattern, bool p_recursive, bool p_owned)
|
|
|
TypedArray<Node> Node::find_children(const String &p_pattern, const String &p_type, bool p_recursive, bool p_owned) const {
|
|
|
TypedArray<Node> ret;
|
|
|
ERR_FAIL_COND_V(p_pattern.is_empty() && p_type.is_empty(), ret);
|
|
|
-
|
|
|
- Node *const *cptr = data.children.ptr();
|
|
|
- int ccount = data.children.size();
|
|
|
+ _update_children_cache();
|
|
|
+ Node *const *cptr = data.children_cache.ptr();
|
|
|
+ int ccount = data.children_cache.size();
|
|
|
for (int i = 0; i < ccount; i++) {
|
|
|
if (p_owned && !cptr[i]->data.owner) {
|
|
|
continue;
|
|
@@ -1526,6 +1509,8 @@ bool Node::is_greater_than(const Node *p_node) const {
|
|
|
ERR_FAIL_COND_V(data.depth < 0, false);
|
|
|
ERR_FAIL_COND_V(p_node->data.depth < 0, false);
|
|
|
|
|
|
+ _update_children_cache();
|
|
|
+
|
|
|
int *this_stack = (int *)alloca(sizeof(int) * data.depth);
|
|
|
int *that_stack = (int *)alloca(sizeof(int) * p_node->data.depth);
|
|
|
|
|
@@ -1534,15 +1519,16 @@ bool Node::is_greater_than(const Node *p_node) const {
|
|
|
int idx = data.depth - 1;
|
|
|
while (n) {
|
|
|
ERR_FAIL_INDEX_V(idx, data.depth, false);
|
|
|
- this_stack[idx--] = n->data.index;
|
|
|
+ this_stack[idx--] = n->get_index();
|
|
|
n = n->data.parent;
|
|
|
}
|
|
|
+
|
|
|
ERR_FAIL_COND_V(idx != -1, false);
|
|
|
n = p_node;
|
|
|
idx = p_node->data.depth - 1;
|
|
|
while (n) {
|
|
|
ERR_FAIL_INDEX_V(idx, p_node->data.depth, false);
|
|
|
- that_stack[idx--] = n->data.index;
|
|
|
+ that_stack[idx--] = n->get_index();
|
|
|
|
|
|
n = n->data.parent;
|
|
|
}
|
|
@@ -1576,8 +1562,8 @@ void Node::get_owned_by(Node *p_by, List<Node *> *p_owned) {
|
|
|
p_owned->push_back(this);
|
|
|
}
|
|
|
|
|
|
- for (int i = 0; i < get_child_count(); i++) {
|
|
|
- get_child(i)->get_owned_by(p_by, p_owned);
|
|
|
+ for (KeyValue<StringName, Node *> &K : data.children) {
|
|
|
+ K.value->get_owned_by(p_by, p_owned);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1895,9 +1881,10 @@ int Node::get_persistent_group_count() const {
|
|
|
void Node::_print_tree_pretty(const String &prefix, const bool last) {
|
|
|
String new_prefix = last ? String::utf8(" ┖╴") : String::utf8(" ┠╴");
|
|
|
print_line(prefix + new_prefix + String(get_name()));
|
|
|
- for (int i = 0; i < data.children.size(); i++) {
|
|
|
+ _update_children_cache();
|
|
|
+ for (uint32_t i = 0; i < data.children_cache.size(); i++) {
|
|
|
new_prefix = last ? String::utf8(" ") : String::utf8(" ┃ ");
|
|
|
- data.children[i]->_print_tree_pretty(prefix + new_prefix, i == data.children.size() - 1);
|
|
|
+ data.children_cache[i]->_print_tree_pretty(prefix + new_prefix, i == data.children_cache.size() - 1);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1911,15 +1898,17 @@ void Node::print_tree() {
|
|
|
|
|
|
void Node::_print_tree(const Node *p_node) {
|
|
|
print_line(String(p_node->get_path_to(this)));
|
|
|
- for (int i = 0; i < data.children.size(); i++) {
|
|
|
- data.children[i]->_print_tree(p_node);
|
|
|
+ _update_children_cache();
|
|
|
+ for (uint32_t i = 0; i < data.children_cache.size(); i++) {
|
|
|
+ data.children_cache[i]->_print_tree(p_node);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void Node::_propagate_reverse_notification(int p_notification) {
|
|
|
data.blocked++;
|
|
|
- for (int i = data.children.size() - 1; i >= 0; i--) {
|
|
|
- data.children[i]->_propagate_reverse_notification(p_notification);
|
|
|
+
|
|
|
+ for (HashMap<StringName, Node *>::Iterator I = data.children.last(); I; --I) {
|
|
|
+ I->value->_propagate_reverse_notification(p_notification);
|
|
|
}
|
|
|
|
|
|
notification(p_notification, true);
|
|
@@ -1935,8 +1924,8 @@ void Node::_propagate_deferred_notification(int p_notification, bool p_reverse)
|
|
|
MessageQueue::get_singleton()->push_notification(this, p_notification);
|
|
|
}
|
|
|
|
|
|
- for (int i = 0; i < data.children.size(); i++) {
|
|
|
- data.children[i]->_propagate_deferred_notification(p_notification, p_reverse);
|
|
|
+ for (KeyValue<StringName, Node *> &K : data.children) {
|
|
|
+ K.value->_propagate_deferred_notification(p_notification, p_reverse);
|
|
|
}
|
|
|
|
|
|
if (p_reverse) {
|
|
@@ -1950,8 +1939,8 @@ void Node::propagate_notification(int p_notification) {
|
|
|
data.blocked++;
|
|
|
notification(p_notification);
|
|
|
|
|
|
- for (int i = 0; i < data.children.size(); i++) {
|
|
|
- data.children[i]->propagate_notification(p_notification);
|
|
|
+ for (KeyValue<StringName, Node *> &K : data.children) {
|
|
|
+ K.value->propagate_notification(p_notification);
|
|
|
}
|
|
|
data.blocked--;
|
|
|
}
|
|
@@ -1963,8 +1952,8 @@ void Node::propagate_call(const StringName &p_method, const Array &p_args, const
|
|
|
callv(p_method, p_args);
|
|
|
}
|
|
|
|
|
|
- for (int i = 0; i < data.children.size(); i++) {
|
|
|
- data.children[i]->propagate_call(p_method, p_args, p_parent_first);
|
|
|
+ for (KeyValue<StringName, Node *> &K : data.children) {
|
|
|
+ K.value->propagate_call(p_method, p_args, p_parent_first);
|
|
|
}
|
|
|
|
|
|
if (!p_parent_first && has_method(p_method)) {
|
|
@@ -1980,22 +1969,12 @@ void Node::_propagate_replace_owner(Node *p_owner, Node *p_by_owner) {
|
|
|
}
|
|
|
|
|
|
data.blocked++;
|
|
|
- for (int i = 0; i < data.children.size(); i++) {
|
|
|
- data.children[i]->_propagate_replace_owner(p_owner, p_by_owner);
|
|
|
+ for (KeyValue<StringName, Node *> &K : data.children) {
|
|
|
+ K.value->_propagate_replace_owner(p_owner, p_by_owner);
|
|
|
}
|
|
|
data.blocked--;
|
|
|
}
|
|
|
|
|
|
-int Node::get_index(bool p_include_internal) const {
|
|
|
- // p_include_internal = false doesn't make sense if the node is internal.
|
|
|
- ERR_FAIL_COND_V_MSG(!p_include_internal && (_is_internal_front() || _is_internal_back()), -1, "Node is internal. Can't get index with 'include_internal' being false.");
|
|
|
-
|
|
|
- if (data.parent && !p_include_internal) {
|
|
|
- return data.index - data.parent->data.internal_children_front;
|
|
|
- }
|
|
|
- return data.index;
|
|
|
-}
|
|
|
-
|
|
|
Ref<Tween> Node::create_tween() {
|
|
|
ERR_FAIL_COND_V_MSG(!data.tree, nullptr, "Can't create Tween when not inside scene tree.");
|
|
|
Ref<Tween> tween = get_tree()->create_tween();
|
|
@@ -2502,7 +2481,7 @@ void Node::replace_by(Node *p_node, bool p_keep_groups) {
|
|
|
}
|
|
|
|
|
|
Node *parent = data.parent;
|
|
|
- int index_in_parent = data.index;
|
|
|
+ int index_in_parent = get_index();
|
|
|
|
|
|
if (data.parent) {
|
|
|
parent->remove_child(this);
|
|
@@ -2754,8 +2733,8 @@ void Node::get_argument_options(const StringName &p_function, int p_idx, List<St
|
|
|
|
|
|
void Node::clear_internal_tree_resource_paths() {
|
|
|
clear_internal_resource_paths();
|
|
|
- for (int i = 0; i < data.children.size(); i++) {
|
|
|
- data.children[i]->clear_internal_tree_resource_paths();
|
|
|
+ for (KeyValue<StringName, Node *> &K : data.children) {
|
|
|
+ K.value->clear_internal_tree_resource_paths();
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -3102,9 +3081,10 @@ Node::~Node() {
|
|
|
data.grouped.clear();
|
|
|
data.owned.clear();
|
|
|
data.children.clear();
|
|
|
+ data.children_cache.clear();
|
|
|
|
|
|
ERR_FAIL_COND(data.parent);
|
|
|
- ERR_FAIL_COND(data.children.size());
|
|
|
+ ERR_FAIL_COND(data.children_cache.size());
|
|
|
|
|
|
orphan_node_count--;
|
|
|
}
|