| 1 | /**************************************************************************/ | 
|---|
| 2 | /*  node.cpp                                                              */ | 
|---|
| 3 | /**************************************************************************/ | 
|---|
| 4 | /*                         This file is part of:                          */ | 
|---|
| 5 | /*                             GODOT ENGINE                               */ | 
|---|
| 6 | /*                        https://godotengine.org                         */ | 
|---|
| 7 | /**************************************************************************/ | 
|---|
| 8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ | 
|---|
| 9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */ | 
|---|
| 10 | /*                                                                        */ | 
|---|
| 11 | /* Permission is hereby granted, free of charge, to any person obtaining  */ | 
|---|
| 12 | /* a copy of this software and associated documentation files (the        */ | 
|---|
| 13 | /* "Software"), to deal in the Software without restriction, including    */ | 
|---|
| 14 | /* without limitation the rights to use, copy, modify, merge, publish,    */ | 
|---|
| 15 | /* distribute, sublicense, and/or sell copies of the Software, and to     */ | 
|---|
| 16 | /* permit persons to whom the Software is furnished to do so, subject to  */ | 
|---|
| 17 | /* the following conditions:                                              */ | 
|---|
| 18 | /*                                                                        */ | 
|---|
| 19 | /* The above copyright notice and this permission notice shall be         */ | 
|---|
| 20 | /* included in all copies or substantial portions of the Software.        */ | 
|---|
| 21 | /*                                                                        */ | 
|---|
| 22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */ | 
|---|
| 23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */ | 
|---|
| 24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ | 
|---|
| 25 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */ | 
|---|
| 26 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */ | 
|---|
| 27 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */ | 
|---|
| 28 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */ | 
|---|
| 29 | /**************************************************************************/ | 
|---|
| 30 |  | 
|---|
| 31 | #include "node.h" | 
|---|
| 32 |  | 
|---|
| 33 | #include "core/config/project_settings.h" | 
|---|
| 34 | #include "core/core_string_names.h" | 
|---|
| 35 | #include "core/io/resource_loader.h" | 
|---|
| 36 | #include "core/object/message_queue.h" | 
|---|
| 37 | #include "core/object/script_language.h" | 
|---|
| 38 | #include "core/string/print_string.h" | 
|---|
| 39 | #include "instance_placeholder.h" | 
|---|
| 40 | #include "scene/animation/tween.h" | 
|---|
| 41 | #include "scene/debugger/scene_debugger.h" | 
|---|
| 42 | #include "scene/main/multiplayer_api.h" | 
|---|
| 43 | #include "scene/main/window.h" | 
|---|
| 44 | #include "scene/resources/packed_scene.h" | 
|---|
| 45 | #include "scene/scene_string_names.h" | 
|---|
| 46 | #include "viewport.h" | 
|---|
| 47 |  | 
|---|
| 48 | #include <stdint.h> | 
|---|
| 49 |  | 
|---|
| 50 | int Node::orphan_node_count = 0; | 
|---|
| 51 |  | 
|---|
| 52 | thread_local Node *Node::current_process_thread_group = nullptr; | 
|---|
| 53 |  | 
|---|
| 54 | void Node::_notification(int p_notification) { | 
|---|
| 55 | switch (p_notification) { | 
|---|
| 56 | case NOTIFICATION_PROCESS: { | 
|---|
| 57 | GDVIRTUAL_CALL(_process, get_process_delta_time()); | 
|---|
| 58 | } break; | 
|---|
| 59 |  | 
|---|
| 60 | case NOTIFICATION_PHYSICS_PROCESS: { | 
|---|
| 61 | GDVIRTUAL_CALL(_physics_process, get_physics_process_delta_time()); | 
|---|
| 62 | } break; | 
|---|
| 63 |  | 
|---|
| 64 | case NOTIFICATION_ENTER_TREE: { | 
|---|
| 65 | ERR_FAIL_NULL(get_viewport()); | 
|---|
| 66 | ERR_FAIL_NULL(get_tree()); | 
|---|
| 67 |  | 
|---|
| 68 | // Update process mode. | 
|---|
| 69 | if (data.process_mode == PROCESS_MODE_INHERIT) { | 
|---|
| 70 | if (data.parent) { | 
|---|
| 71 | data.process_owner = data.parent->data.process_owner; | 
|---|
| 72 | } else { | 
|---|
| 73 | ERR_PRINT( "The root node can't be set to Inherit process mode, reverting to Pausable instead."); | 
|---|
| 74 | data.process_mode = PROCESS_MODE_PAUSABLE; | 
|---|
| 75 | data.process_owner = this; | 
|---|
| 76 | } | 
|---|
| 77 | } else { | 
|---|
| 78 | data.process_owner = this; | 
|---|
| 79 | } | 
|---|
| 80 |  | 
|---|
| 81 | { // Update threaded process mode. | 
|---|
| 82 | if (data.process_thread_group == PROCESS_THREAD_GROUP_INHERIT) { | 
|---|
| 83 | if (data.parent) { | 
|---|
| 84 | data.process_thread_group_owner = data.parent->data.process_thread_group_owner; | 
|---|
| 85 | } | 
|---|
| 86 |  | 
|---|
| 87 | if (data.process_thread_group_owner) { | 
|---|
| 88 | data.process_group = data.process_thread_group_owner->data.process_group; | 
|---|
| 89 | } else { | 
|---|
| 90 | data.process_group = &data.tree->default_process_group; | 
|---|
| 91 | } | 
|---|
| 92 | } else { | 
|---|
| 93 | data.process_thread_group_owner = this; | 
|---|
| 94 | _add_process_group(); | 
|---|
| 95 | } | 
|---|
| 96 |  | 
|---|
| 97 | if (_is_any_processing()) { | 
|---|
| 98 | _add_to_process_thread_group(); | 
|---|
| 99 | } | 
|---|
| 100 | } | 
|---|
| 101 |  | 
|---|
| 102 | if (data.input) { | 
|---|
| 103 | add_to_group( "_vp_input"+ itos(get_viewport()->get_instance_id())); | 
|---|
| 104 | } | 
|---|
| 105 | if (data.shortcut_input) { | 
|---|
| 106 | add_to_group( "_vp_shortcut_input"+ itos(get_viewport()->get_instance_id())); | 
|---|
| 107 | } | 
|---|
| 108 | if (data.unhandled_input) { | 
|---|
| 109 | add_to_group( "_vp_unhandled_input"+ itos(get_viewport()->get_instance_id())); | 
|---|
| 110 | } | 
|---|
| 111 | if (data.unhandled_key_input) { | 
|---|
| 112 | add_to_group( "_vp_unhandled_key_input"+ itos(get_viewport()->get_instance_id())); | 
|---|
| 113 | } | 
|---|
| 114 |  | 
|---|
| 115 | get_tree()->nodes_in_tree_count++; | 
|---|
| 116 | orphan_node_count--; | 
|---|
| 117 | } break; | 
|---|
| 118 |  | 
|---|
| 119 | case NOTIFICATION_EXIT_TREE: { | 
|---|
| 120 | ERR_FAIL_NULL(get_viewport()); | 
|---|
| 121 | ERR_FAIL_NULL(get_tree()); | 
|---|
| 122 |  | 
|---|
| 123 | get_tree()->nodes_in_tree_count--; | 
|---|
| 124 | orphan_node_count++; | 
|---|
| 125 |  | 
|---|
| 126 | if (data.input) { | 
|---|
| 127 | remove_from_group( "_vp_input"+ itos(get_viewport()->get_instance_id())); | 
|---|
| 128 | } | 
|---|
| 129 | if (data.shortcut_input) { | 
|---|
| 130 | remove_from_group( "_vp_shortcut_input"+ itos(get_viewport()->get_instance_id())); | 
|---|
| 131 | } | 
|---|
| 132 | if (data.unhandled_input) { | 
|---|
| 133 | remove_from_group( "_vp_unhandled_input"+ itos(get_viewport()->get_instance_id())); | 
|---|
| 134 | } | 
|---|
| 135 | if (data.unhandled_key_input) { | 
|---|
| 136 | remove_from_group( "_vp_unhandled_key_input"+ itos(get_viewport()->get_instance_id())); | 
|---|
| 137 | } | 
|---|
| 138 |  | 
|---|
| 139 | // Remove from processing first | 
|---|
| 140 | if (_is_any_processing()) { | 
|---|
| 141 | _remove_from_process_thread_group(); | 
|---|
| 142 | } | 
|---|
| 143 | // Remove the process group | 
|---|
| 144 | if (data.process_thread_group_owner == this) { | 
|---|
| 145 | _remove_process_group(); | 
|---|
| 146 | } | 
|---|
| 147 | data.process_thread_group_owner = nullptr; | 
|---|
| 148 | data.process_owner = nullptr; | 
|---|
| 149 |  | 
|---|
| 150 | if (data.path_cache) { | 
|---|
| 151 | memdelete(data.path_cache); | 
|---|
| 152 | data.path_cache = nullptr; | 
|---|
| 153 | } | 
|---|
| 154 | } break; | 
|---|
| 155 |  | 
|---|
| 156 | case NOTIFICATION_PATH_RENAMED: { | 
|---|
| 157 | if (data.path_cache) { | 
|---|
| 158 | memdelete(data.path_cache); | 
|---|
| 159 | data.path_cache = nullptr; | 
|---|
| 160 | } | 
|---|
| 161 | } break; | 
|---|
| 162 |  | 
|---|
| 163 | case NOTIFICATION_READY: { | 
|---|
| 164 | if (GDVIRTUAL_IS_OVERRIDDEN(_input)) { | 
|---|
| 165 | set_process_input(true); | 
|---|
| 166 | } | 
|---|
| 167 |  | 
|---|
| 168 | if (GDVIRTUAL_IS_OVERRIDDEN(_shortcut_input)) { | 
|---|
| 169 | set_process_shortcut_input(true); | 
|---|
| 170 | } | 
|---|
| 171 |  | 
|---|
| 172 | if (GDVIRTUAL_IS_OVERRIDDEN(_unhandled_input)) { | 
|---|
| 173 | set_process_unhandled_input(true); | 
|---|
| 174 | } | 
|---|
| 175 |  | 
|---|
| 176 | if (GDVIRTUAL_IS_OVERRIDDEN(_unhandled_key_input)) { | 
|---|
| 177 | set_process_unhandled_key_input(true); | 
|---|
| 178 | } | 
|---|
| 179 |  | 
|---|
| 180 | if (GDVIRTUAL_IS_OVERRIDDEN(_process)) { | 
|---|
| 181 | set_process(true); | 
|---|
| 182 | } | 
|---|
| 183 | if (GDVIRTUAL_IS_OVERRIDDEN(_physics_process)) { | 
|---|
| 184 | set_physics_process(true); | 
|---|
| 185 | } | 
|---|
| 186 |  | 
|---|
| 187 | GDVIRTUAL_CALL(_ready); | 
|---|
| 188 | } break; | 
|---|
| 189 |  | 
|---|
| 190 | case NOTIFICATION_POSTINITIALIZE: { | 
|---|
| 191 | data.in_constructor = false; | 
|---|
| 192 | } break; | 
|---|
| 193 |  | 
|---|
| 194 | case NOTIFICATION_PREDELETE: { | 
|---|
| 195 | if (data.inside_tree && !Thread::is_main_thread()) { | 
|---|
| 196 | cancel_free(); | 
|---|
| 197 | ERR_PRINT( "Attempted to free a node that is currently added to the SceneTree from a thread. This is not permitted, use queue_free() instead. Node has not been freed."); | 
|---|
| 198 | return; | 
|---|
| 199 | } | 
|---|
| 200 |  | 
|---|
| 201 | if (data.owner) { | 
|---|
| 202 | _clean_up_owner(); | 
|---|
| 203 | } | 
|---|
| 204 |  | 
|---|
| 205 | if (data.parent) { | 
|---|
| 206 | data.parent->remove_child(this); | 
|---|
| 207 | } | 
|---|
| 208 |  | 
|---|
| 209 | // kill children as cleanly as possible | 
|---|
| 210 | while (data.children.size()) { | 
|---|
| 211 | Node *child = data.children.last()->value; // begin from the end because its faster and more consistent with creation | 
|---|
| 212 | memdelete(child); | 
|---|
| 213 | } | 
|---|
| 214 | } break; | 
|---|
| 215 | } | 
|---|
| 216 | } | 
|---|
| 217 |  | 
|---|
| 218 | void Node::_propagate_ready() { | 
|---|
| 219 | data.ready_notified = true; | 
|---|
| 220 | data.blocked++; | 
|---|
| 221 | for (KeyValue<StringName, Node *> &K : data.children) { | 
|---|
| 222 | K.value->_propagate_ready(); | 
|---|
| 223 | } | 
|---|
| 224 |  | 
|---|
| 225 | data.blocked--; | 
|---|
| 226 |  | 
|---|
| 227 | notification(NOTIFICATION_POST_ENTER_TREE); | 
|---|
| 228 |  | 
|---|
| 229 | if (data.ready_first) { | 
|---|
| 230 | data.ready_first = false; | 
|---|
| 231 | notification(NOTIFICATION_READY); | 
|---|
| 232 | emit_signal(SceneStringNames::get_singleton()->ready); | 
|---|
| 233 | } | 
|---|
| 234 | } | 
|---|
| 235 |  | 
|---|
| 236 | void Node::_propagate_enter_tree() { | 
|---|
| 237 | // this needs to happen to all children before any enter_tree | 
|---|
| 238 |  | 
|---|
| 239 | if (data.parent) { | 
|---|
| 240 | data.tree = data.parent->data.tree; | 
|---|
| 241 | data.depth = data.parent->data.depth + 1; | 
|---|
| 242 | } else { | 
|---|
| 243 | data.depth = 1; | 
|---|
| 244 | } | 
|---|
| 245 |  | 
|---|
| 246 | data.viewport = Object::cast_to<Viewport>(this); | 
|---|
| 247 | if (!data.viewport && data.parent) { | 
|---|
| 248 | data.viewport = data.parent->data.viewport; | 
|---|
| 249 | } | 
|---|
| 250 |  | 
|---|
| 251 | data.inside_tree = true; | 
|---|
| 252 |  | 
|---|
| 253 | for (KeyValue<StringName, GroupData> &E : data.grouped) { | 
|---|
| 254 | E.value.group = data.tree->add_to_group(E.key, this); | 
|---|
| 255 | } | 
|---|
| 256 |  | 
|---|
| 257 | notification(NOTIFICATION_ENTER_TREE); | 
|---|
| 258 |  | 
|---|
| 259 | GDVIRTUAL_CALL(_enter_tree); | 
|---|
| 260 |  | 
|---|
| 261 | emit_signal(SceneStringNames::get_singleton()->tree_entered); | 
|---|
| 262 |  | 
|---|
| 263 | data.tree->node_added(this); | 
|---|
| 264 |  | 
|---|
| 265 | if (data.parent) { | 
|---|
| 266 | Variant c = this; | 
|---|
| 267 | const Variant *cptr = &c; | 
|---|
| 268 | data.parent->emit_signalp(SNAME( "child_entered_tree"), &cptr, 1); | 
|---|
| 269 | } | 
|---|
| 270 |  | 
|---|
| 271 | data.blocked++; | 
|---|
| 272 | //block while adding children | 
|---|
| 273 |  | 
|---|
| 274 | for (KeyValue<StringName, Node *> &K : data.children) { | 
|---|
| 275 | if (!K.value->is_inside_tree()) { // could have been added in enter_tree | 
|---|
| 276 | K.value->_propagate_enter_tree(); | 
|---|
| 277 | } | 
|---|
| 278 | } | 
|---|
| 279 |  | 
|---|
| 280 | data.blocked--; | 
|---|
| 281 |  | 
|---|
| 282 | #ifdef DEBUG_ENABLED | 
|---|
| 283 | SceneDebugger::add_to_cache(data.scene_file_path, this); | 
|---|
| 284 | #endif | 
|---|
| 285 | // enter groups | 
|---|
| 286 | } | 
|---|
| 287 |  | 
|---|
| 288 | void Node::_propagate_after_exit_tree() { | 
|---|
| 289 | // Clear owner if it was not part of the pruned branch | 
|---|
| 290 | if (data.owner) { | 
|---|
| 291 | bool found = false; | 
|---|
| 292 | Node *parent = data.parent; | 
|---|
| 293 |  | 
|---|
| 294 | while (parent) { | 
|---|
| 295 | if (parent == data.owner) { | 
|---|
| 296 | found = true; | 
|---|
| 297 | break; | 
|---|
| 298 | } | 
|---|
| 299 |  | 
|---|
| 300 | parent = parent->data.parent; | 
|---|
| 301 | } | 
|---|
| 302 |  | 
|---|
| 303 | if (!found) { | 
|---|
| 304 | _clean_up_owner(); | 
|---|
| 305 | } | 
|---|
| 306 | } | 
|---|
| 307 |  | 
|---|
| 308 | data.blocked++; | 
|---|
| 309 |  | 
|---|
| 310 | for (HashMap<StringName, Node *>::Iterator I = data.children.last(); I; --I) { | 
|---|
| 311 | I->value->_propagate_after_exit_tree(); | 
|---|
| 312 | } | 
|---|
| 313 |  | 
|---|
| 314 | data.blocked--; | 
|---|
| 315 |  | 
|---|
| 316 | emit_signal(SceneStringNames::get_singleton()->tree_exited); | 
|---|
| 317 | } | 
|---|
| 318 |  | 
|---|
| 319 | void Node::_propagate_exit_tree() { | 
|---|
| 320 | //block while removing children | 
|---|
| 321 |  | 
|---|
| 322 | #ifdef DEBUG_ENABLED | 
|---|
| 323 | if (!data.scene_file_path.is_empty()) { | 
|---|
| 324 | // Only remove if file path is set (optimization). | 
|---|
| 325 | SceneDebugger::remove_from_cache(data.scene_file_path, this); | 
|---|
| 326 | } | 
|---|
| 327 | #endif | 
|---|
| 328 | data.blocked++; | 
|---|
| 329 |  | 
|---|
| 330 | for (HashMap<StringName, Node *>::Iterator I = data.children.last(); I; --I) { | 
|---|
| 331 | I->value->_propagate_exit_tree(); | 
|---|
| 332 | } | 
|---|
| 333 |  | 
|---|
| 334 | data.blocked--; | 
|---|
| 335 |  | 
|---|
| 336 | GDVIRTUAL_CALL(_exit_tree); | 
|---|
| 337 |  | 
|---|
| 338 | emit_signal(SceneStringNames::get_singleton()->tree_exiting); | 
|---|
| 339 |  | 
|---|
| 340 | notification(NOTIFICATION_EXIT_TREE, true); | 
|---|
| 341 | if (data.tree) { | 
|---|
| 342 | data.tree->node_removed(this); | 
|---|
| 343 | } | 
|---|
| 344 |  | 
|---|
| 345 | if (data.parent) { | 
|---|
| 346 | Variant c = this; | 
|---|
| 347 | const Variant *cptr = &c; | 
|---|
| 348 | data.parent->emit_signalp(SNAME( "child_exiting_tree"), &cptr, 1); | 
|---|
| 349 | } | 
|---|
| 350 |  | 
|---|
| 351 | // exit groups | 
|---|
| 352 | for (KeyValue<StringName, GroupData> &E : data.grouped) { | 
|---|
| 353 | data.tree->remove_from_group(E.key, this); | 
|---|
| 354 | E.value.group = nullptr; | 
|---|
| 355 | } | 
|---|
| 356 |  | 
|---|
| 357 | data.viewport = nullptr; | 
|---|
| 358 |  | 
|---|
| 359 | if (data.tree) { | 
|---|
| 360 | data.tree->tree_changed(); | 
|---|
| 361 | } | 
|---|
| 362 |  | 
|---|
| 363 | data.inside_tree = false; | 
|---|
| 364 | data.ready_notified = false; | 
|---|
| 365 | data.tree = nullptr; | 
|---|
| 366 | data.depth = -1; | 
|---|
| 367 | } | 
|---|
| 368 |  | 
|---|
| 369 | void Node::move_child(Node *p_child, int p_index) { | 
|---|
| 370 | ERR_FAIL_COND_MSG(data.inside_tree && !Thread::is_main_thread(), "Moving child node positions inside the SceneTree is only allowed from the main thread. Use call_deferred(\"move_child\",child,index)."); | 
|---|
| 371 | ERR_FAIL_NULL(p_child); | 
|---|
| 372 | ERR_FAIL_COND_MSG(p_child->data.parent != this, "Child is not a child of this node."); | 
|---|
| 373 |  | 
|---|
| 374 | _update_children_cache(); | 
|---|
| 375 | // We need to check whether node is internal and move it only in the relevant node range. | 
|---|
| 376 | if (p_child->data.internal_mode == INTERNAL_MODE_FRONT) { | 
|---|
| 377 | if (p_index < 0) { | 
|---|
| 378 | p_index += data.internal_children_front_count_cache; | 
|---|
| 379 | } | 
|---|
| 380 | ERR_FAIL_INDEX_MSG(p_index, data.internal_children_front_count_cache, vformat( "Invalid new child index: %d. Child is internal.", p_index)); | 
|---|
| 381 | _move_child(p_child, p_index); | 
|---|
| 382 | } else if (p_child->data.internal_mode == INTERNAL_MODE_BACK) { | 
|---|
| 383 | if (p_index < 0) { | 
|---|
| 384 | p_index += data.internal_children_back_count_cache; | 
|---|
| 385 | } | 
|---|
| 386 | ERR_FAIL_INDEX_MSG(p_index, data.internal_children_back_count_cache, vformat( "Invalid new child index: %d. Child is internal.", p_index)); | 
|---|
| 387 | _move_child(p_child, (int)data.children_cache.size() - data.internal_children_back_count_cache + p_index); | 
|---|
| 388 | } else { | 
|---|
| 389 | if (p_index < 0) { | 
|---|
| 390 | p_index += get_child_count(false); | 
|---|
| 391 | } | 
|---|
| 392 | 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)); | 
|---|
| 393 | _move_child(p_child, p_index + data.internal_children_front_count_cache); | 
|---|
| 394 | } | 
|---|
| 395 | } | 
|---|
| 396 |  | 
|---|
| 397 | void Node::_move_child(Node *p_child, int p_index, bool p_ignore_end) { | 
|---|
| 398 | ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, `move_child()` failed. Consider using `move_child.call_deferred(child, index)` instead (or `popup.call_deferred()` if this is from a popup)."); | 
|---|
| 399 |  | 
|---|
| 400 | // Specifying one place beyond the end | 
|---|
| 401 | // means the same as moving to the last index | 
|---|
| 402 | if (!p_ignore_end) { // p_ignore_end is a little hack to make back internal children work properly. | 
|---|
| 403 | if (p_child->data.internal_mode == INTERNAL_MODE_FRONT) { | 
|---|
| 404 | if (p_index == data.internal_children_front_count_cache) { | 
|---|
| 405 | p_index--; | 
|---|
| 406 | } | 
|---|
| 407 | } else if (p_child->data.internal_mode == INTERNAL_MODE_BACK) { | 
|---|
| 408 | if (p_index == (int)data.children_cache.size()) { | 
|---|
| 409 | p_index--; | 
|---|
| 410 | } | 
|---|
| 411 | } else { | 
|---|
| 412 | if (p_index == (int)data.children_cache.size() - data.internal_children_back_count_cache) { | 
|---|
| 413 | p_index--; | 
|---|
| 414 | } | 
|---|
| 415 | } | 
|---|
| 416 | } | 
|---|
| 417 |  | 
|---|
| 418 | int child_index = p_child->get_index(); | 
|---|
| 419 |  | 
|---|
| 420 | if (child_index == p_index) { | 
|---|
| 421 | return; //do nothing | 
|---|
| 422 | } | 
|---|
| 423 |  | 
|---|
| 424 | int motion_from = MIN(p_index, child_index); | 
|---|
| 425 | int motion_to = MAX(p_index, child_index); | 
|---|
| 426 |  | 
|---|
| 427 | data.children_cache.remove_at(child_index); | 
|---|
| 428 | data.children_cache.insert(p_index, p_child); | 
|---|
| 429 |  | 
|---|
| 430 | if (data.tree) { | 
|---|
| 431 | data.tree->tree_changed(); | 
|---|
| 432 | } | 
|---|
| 433 |  | 
|---|
| 434 | data.blocked++; | 
|---|
| 435 | //new pos first | 
|---|
| 436 | for (int i = motion_from; i <= motion_to; i++) { | 
|---|
| 437 | if (data.children_cache[i]->data.internal_mode == INTERNAL_MODE_DISABLED) { | 
|---|
| 438 | data.children_cache[i]->data.index = i - data.internal_children_front_count_cache; | 
|---|
| 439 | } else if (data.children_cache[i]->data.internal_mode == INTERNAL_MODE_BACK) { | 
|---|
| 440 | data.children_cache[i]->data.index = i - data.internal_children_front_count_cache - data.external_children_count_cache; | 
|---|
| 441 | } else { | 
|---|
| 442 | data.children_cache[i]->data.index = i; | 
|---|
| 443 | } | 
|---|
| 444 | } | 
|---|
| 445 | // notification second | 
|---|
| 446 | move_child_notify(p_child); | 
|---|
| 447 | notification(NOTIFICATION_CHILD_ORDER_CHANGED); | 
|---|
| 448 | emit_signal(SNAME( "child_order_changed")); | 
|---|
| 449 | p_child->_propagate_groups_dirty(); | 
|---|
| 450 |  | 
|---|
| 451 | data.blocked--; | 
|---|
| 452 | } | 
|---|
| 453 |  | 
|---|
| 454 | void Node::_propagate_groups_dirty() { | 
|---|
| 455 | for (const KeyValue<StringName, GroupData> &E : data.grouped) { | 
|---|
| 456 | if (E.value.group) { | 
|---|
| 457 | E.value.group->changed = true; | 
|---|
| 458 | } | 
|---|
| 459 | } | 
|---|
| 460 |  | 
|---|
| 461 | for (KeyValue<StringName, Node *> &K : data.children) { | 
|---|
| 462 | K.value->_propagate_groups_dirty(); | 
|---|
| 463 | } | 
|---|
| 464 | } | 
|---|
| 465 |  | 
|---|
| 466 | void Node::add_child_notify(Node *p_child) { | 
|---|
| 467 | // to be used when not wanted | 
|---|
| 468 | } | 
|---|
| 469 |  | 
|---|
| 470 | void Node::remove_child_notify(Node *p_child) { | 
|---|
| 471 | // to be used when not wanted | 
|---|
| 472 | } | 
|---|
| 473 |  | 
|---|
| 474 | void Node::move_child_notify(Node *p_child) { | 
|---|
| 475 | // to be used when not wanted | 
|---|
| 476 | } | 
|---|
| 477 |  | 
|---|
| 478 | void Node::owner_changed_notify() { | 
|---|
| 479 | } | 
|---|
| 480 |  | 
|---|
| 481 | void Node::set_physics_process(bool p_process) { | 
|---|
| 482 | ERR_THREAD_GUARD | 
|---|
| 483 | if (data.physics_process == p_process) { | 
|---|
| 484 | return; | 
|---|
| 485 | } | 
|---|
| 486 |  | 
|---|
| 487 | if (!is_inside_tree()) { | 
|---|
| 488 | data.physics_process = p_process; | 
|---|
| 489 | return; | 
|---|
| 490 | } | 
|---|
| 491 |  | 
|---|
| 492 | if (_is_any_processing()) { | 
|---|
| 493 | _remove_from_process_thread_group(); | 
|---|
| 494 | } | 
|---|
| 495 |  | 
|---|
| 496 | data.physics_process = p_process; | 
|---|
| 497 |  | 
|---|
| 498 | if (_is_any_processing()) { | 
|---|
| 499 | _add_to_process_thread_group(); | 
|---|
| 500 | } | 
|---|
| 501 | } | 
|---|
| 502 |  | 
|---|
| 503 | bool Node::is_physics_processing() const { | 
|---|
| 504 | return data.physics_process; | 
|---|
| 505 | } | 
|---|
| 506 |  | 
|---|
| 507 | void Node::set_physics_process_internal(bool p_process_internal) { | 
|---|
| 508 | ERR_THREAD_GUARD | 
|---|
| 509 | if (data.physics_process_internal == p_process_internal) { | 
|---|
| 510 | return; | 
|---|
| 511 | } | 
|---|
| 512 |  | 
|---|
| 513 | if (!is_inside_tree()) { | 
|---|
| 514 | data.physics_process_internal = p_process_internal; | 
|---|
| 515 | return; | 
|---|
| 516 | } | 
|---|
| 517 |  | 
|---|
| 518 | if (_is_any_processing()) { | 
|---|
| 519 | _remove_from_process_thread_group(); | 
|---|
| 520 | } | 
|---|
| 521 |  | 
|---|
| 522 | data.physics_process_internal = p_process_internal; | 
|---|
| 523 |  | 
|---|
| 524 | if (_is_any_processing()) { | 
|---|
| 525 | _add_to_process_thread_group(); | 
|---|
| 526 | } | 
|---|
| 527 | } | 
|---|
| 528 |  | 
|---|
| 529 | bool Node::is_physics_processing_internal() const { | 
|---|
| 530 | return data.physics_process_internal; | 
|---|
| 531 | } | 
|---|
| 532 |  | 
|---|
| 533 | void Node::set_process_mode(ProcessMode p_mode) { | 
|---|
| 534 | ERR_THREAD_GUARD | 
|---|
| 535 | if (data.process_mode == p_mode) { | 
|---|
| 536 | return; | 
|---|
| 537 | } | 
|---|
| 538 |  | 
|---|
| 539 | if (!is_inside_tree()) { | 
|---|
| 540 | data.process_mode = p_mode; | 
|---|
| 541 | return; | 
|---|
| 542 | } | 
|---|
| 543 |  | 
|---|
| 544 | bool prev_can_process = can_process(); | 
|---|
| 545 | bool prev_enabled = _is_enabled(); | 
|---|
| 546 |  | 
|---|
| 547 | if (p_mode == PROCESS_MODE_INHERIT) { | 
|---|
| 548 | if (data.parent) { | 
|---|
| 549 | data.process_owner = data.parent->data.process_owner; | 
|---|
| 550 | } else { | 
|---|
| 551 | ERR_FAIL_MSG( "The root node can't be set to Inherit process mode."); | 
|---|
| 552 | } | 
|---|
| 553 | } else { | 
|---|
| 554 | data.process_owner = this; | 
|---|
| 555 | } | 
|---|
| 556 |  | 
|---|
| 557 | data.process_mode = p_mode; | 
|---|
| 558 |  | 
|---|
| 559 | bool next_can_process = can_process(); | 
|---|
| 560 | bool next_enabled = _is_enabled(); | 
|---|
| 561 |  | 
|---|
| 562 | int pause_notification = 0; | 
|---|
| 563 |  | 
|---|
| 564 | if (prev_can_process && !next_can_process) { | 
|---|
| 565 | pause_notification = NOTIFICATION_PAUSED; | 
|---|
| 566 | } else if (!prev_can_process && next_can_process) { | 
|---|
| 567 | pause_notification = NOTIFICATION_UNPAUSED; | 
|---|
| 568 | } | 
|---|
| 569 |  | 
|---|
| 570 | int enabled_notification = 0; | 
|---|
| 571 |  | 
|---|
| 572 | if (prev_enabled && !next_enabled) { | 
|---|
| 573 | enabled_notification = NOTIFICATION_DISABLED; | 
|---|
| 574 | } else if (!prev_enabled && next_enabled) { | 
|---|
| 575 | enabled_notification = NOTIFICATION_ENABLED; | 
|---|
| 576 | } | 
|---|
| 577 |  | 
|---|
| 578 | _propagate_process_owner(data.process_owner, pause_notification, enabled_notification); | 
|---|
| 579 |  | 
|---|
| 580 | #ifdef TOOLS_ENABLED | 
|---|
| 581 | // This is required for the editor to update the visibility of disabled nodes | 
|---|
| 582 | // It's very expensive during runtime to change, so editor-only | 
|---|
| 583 | if (Engine::get_singleton()->is_editor_hint()) { | 
|---|
| 584 | get_tree()->emit_signal(SNAME( "tree_process_mode_changed")); | 
|---|
| 585 | } | 
|---|
| 586 | #endif | 
|---|
| 587 | } | 
|---|
| 588 |  | 
|---|
| 589 | void Node::_propagate_pause_notification(bool p_enable) { | 
|---|
| 590 | bool prev_can_process = _can_process(!p_enable); | 
|---|
| 591 | bool next_can_process = _can_process(p_enable); | 
|---|
| 592 |  | 
|---|
| 593 | if (prev_can_process && !next_can_process) { | 
|---|
| 594 | notification(NOTIFICATION_PAUSED); | 
|---|
| 595 | } else if (!prev_can_process && next_can_process) { | 
|---|
| 596 | notification(NOTIFICATION_UNPAUSED); | 
|---|
| 597 | } | 
|---|
| 598 |  | 
|---|
| 599 | data.blocked++; | 
|---|
| 600 | for (KeyValue<StringName, Node *> &K : data.children) { | 
|---|
| 601 | K.value->_propagate_pause_notification(p_enable); | 
|---|
| 602 | } | 
|---|
| 603 | data.blocked--; | 
|---|
| 604 | } | 
|---|
| 605 |  | 
|---|
| 606 | Node::ProcessMode Node::get_process_mode() const { | 
|---|
| 607 | return data.process_mode; | 
|---|
| 608 | } | 
|---|
| 609 |  | 
|---|
| 610 | void Node::_propagate_process_owner(Node *p_owner, int p_pause_notification, int p_enabled_notification) { | 
|---|
| 611 | data.process_owner = p_owner; | 
|---|
| 612 |  | 
|---|
| 613 | if (p_pause_notification != 0) { | 
|---|
| 614 | notification(p_pause_notification); | 
|---|
| 615 | } | 
|---|
| 616 |  | 
|---|
| 617 | if (p_enabled_notification != 0) { | 
|---|
| 618 | notification(p_enabled_notification); | 
|---|
| 619 | } | 
|---|
| 620 |  | 
|---|
| 621 | data.blocked++; | 
|---|
| 622 | for (KeyValue<StringName, Node *> &K : data.children) { | 
|---|
| 623 | Node *c = K.value; | 
|---|
| 624 | if (c->data.process_mode == PROCESS_MODE_INHERIT) { | 
|---|
| 625 | c->_propagate_process_owner(p_owner, p_pause_notification, p_enabled_notification); | 
|---|
| 626 | } | 
|---|
| 627 | } | 
|---|
| 628 | data.blocked--; | 
|---|
| 629 | } | 
|---|
| 630 |  | 
|---|
| 631 | void Node::set_multiplayer_authority(int p_peer_id, bool p_recursive) { | 
|---|
| 632 | ERR_THREAD_GUARD | 
|---|
| 633 | data.multiplayer_authority = p_peer_id; | 
|---|
| 634 |  | 
|---|
| 635 | if (p_recursive) { | 
|---|
| 636 | for (KeyValue<StringName, Node *> &K : data.children) { | 
|---|
| 637 | K.value->set_multiplayer_authority(p_peer_id, true); | 
|---|
| 638 | } | 
|---|
| 639 | } | 
|---|
| 640 | } | 
|---|
| 641 |  | 
|---|
| 642 | int Node::get_multiplayer_authority() const { | 
|---|
| 643 | return data.multiplayer_authority; | 
|---|
| 644 | } | 
|---|
| 645 |  | 
|---|
| 646 | bool Node::is_multiplayer_authority() const { | 
|---|
| 647 | ERR_FAIL_COND_V(!is_inside_tree(), false); | 
|---|
| 648 |  | 
|---|
| 649 | Ref<MultiplayerAPI> api = get_multiplayer(); | 
|---|
| 650 | return api.is_valid() && (api->get_unique_id() == data.multiplayer_authority); | 
|---|
| 651 | } | 
|---|
| 652 |  | 
|---|
| 653 | /***** RPC CONFIG ********/ | 
|---|
| 654 |  | 
|---|
| 655 | void Node::rpc_config(const StringName &p_method, const Variant &p_config) { | 
|---|
| 656 | ERR_THREAD_GUARD | 
|---|
| 657 | if (data.rpc_config.get_type() != Variant::DICTIONARY) { | 
|---|
| 658 | data.rpc_config = Dictionary(); | 
|---|
| 659 | } | 
|---|
| 660 | Dictionary node_config = data.rpc_config; | 
|---|
| 661 | if (p_config.get_type() == Variant::NIL) { | 
|---|
| 662 | node_config.erase(p_method); | 
|---|
| 663 | } else { | 
|---|
| 664 | ERR_FAIL_COND(p_config.get_type() != Variant::DICTIONARY); | 
|---|
| 665 | node_config[p_method] = p_config; | 
|---|
| 666 | } | 
|---|
| 667 | } | 
|---|
| 668 |  | 
|---|
| 669 | const Variant Node::get_node_rpc_config() const { | 
|---|
| 670 | return data.rpc_config; | 
|---|
| 671 | } | 
|---|
| 672 |  | 
|---|
| 673 | /***** RPC FUNCTIONS ********/ | 
|---|
| 674 |  | 
|---|
| 675 | Error Node::_rpc_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { | 
|---|
| 676 | if (p_argcount < 1) { | 
|---|
| 677 | r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; | 
|---|
| 678 | r_error.argument = 1; | 
|---|
| 679 | return ERR_INVALID_PARAMETER; | 
|---|
| 680 | } | 
|---|
| 681 |  | 
|---|
| 682 | Variant::Type type = p_args[0]->get_type(); | 
|---|
| 683 | if (type != Variant::STRING_NAME && type != Variant::STRING) { | 
|---|
| 684 | r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; | 
|---|
| 685 | r_error.argument = 0; | 
|---|
| 686 | r_error.expected = Variant::STRING_NAME; | 
|---|
| 687 | return ERR_INVALID_PARAMETER; | 
|---|
| 688 | } | 
|---|
| 689 |  | 
|---|
| 690 | StringName method = (*p_args[0]).operator StringName(); | 
|---|
| 691 |  | 
|---|
| 692 | Error err = rpcp(0, method, &p_args[1], p_argcount - 1); | 
|---|
| 693 | r_error.error = Callable::CallError::CALL_OK; | 
|---|
| 694 | return err; | 
|---|
| 695 | } | 
|---|
| 696 |  | 
|---|
| 697 | Error Node::_rpc_id_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { | 
|---|
| 698 | if (p_argcount < 2) { | 
|---|
| 699 | r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; | 
|---|
| 700 | r_error.argument = 2; | 
|---|
| 701 | return ERR_INVALID_PARAMETER; | 
|---|
| 702 | } | 
|---|
| 703 |  | 
|---|
| 704 | if (p_args[0]->get_type() != Variant::INT) { | 
|---|
| 705 | r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; | 
|---|
| 706 | r_error.argument = 0; | 
|---|
| 707 | r_error.expected = Variant::INT; | 
|---|
| 708 | return ERR_INVALID_PARAMETER; | 
|---|
| 709 | } | 
|---|
| 710 |  | 
|---|
| 711 | Variant::Type type = p_args[1]->get_type(); | 
|---|
| 712 | if (type != Variant::STRING_NAME && type != Variant::STRING) { | 
|---|
| 713 | r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; | 
|---|
| 714 | r_error.argument = 1; | 
|---|
| 715 | r_error.expected = Variant::STRING_NAME; | 
|---|
| 716 | return ERR_INVALID_PARAMETER; | 
|---|
| 717 | } | 
|---|
| 718 |  | 
|---|
| 719 | int peer_id = *p_args[0]; | 
|---|
| 720 | StringName method = (*p_args[1]).operator StringName(); | 
|---|
| 721 |  | 
|---|
| 722 | Error err = rpcp(peer_id, method, &p_args[2], p_argcount - 2); | 
|---|
| 723 | r_error.error = Callable::CallError::CALL_OK; | 
|---|
| 724 | return err; | 
|---|
| 725 | } | 
|---|
| 726 |  | 
|---|
| 727 | Error Node::rpcp(int p_peer_id, const StringName &p_method, const Variant **p_arg, int p_argcount) { | 
|---|
| 728 | ERR_FAIL_COND_V(!is_inside_tree(), ERR_UNCONFIGURED); | 
|---|
| 729 |  | 
|---|
| 730 | Ref<MultiplayerAPI> api = get_multiplayer(); | 
|---|
| 731 | if (api.is_null()) { | 
|---|
| 732 | return ERR_UNCONFIGURED; | 
|---|
| 733 | } | 
|---|
| 734 | return api->rpcp(this, p_peer_id, p_method, p_arg, p_argcount); | 
|---|
| 735 | } | 
|---|
| 736 |  | 
|---|
| 737 | Ref<MultiplayerAPI> Node::get_multiplayer() const { | 
|---|
| 738 | if (!is_inside_tree()) { | 
|---|
| 739 | return Ref<MultiplayerAPI>(); | 
|---|
| 740 | } | 
|---|
| 741 | return get_tree()->get_multiplayer(get_path()); | 
|---|
| 742 | } | 
|---|
| 743 |  | 
|---|
| 744 | //////////// end of rpc | 
|---|
| 745 |  | 
|---|
| 746 | bool Node::can_process_notification(int p_what) const { | 
|---|
| 747 | switch (p_what) { | 
|---|
| 748 | case NOTIFICATION_PHYSICS_PROCESS: | 
|---|
| 749 | return data.physics_process; | 
|---|
| 750 | case NOTIFICATION_PROCESS: | 
|---|
| 751 | return data.process; | 
|---|
| 752 | case NOTIFICATION_INTERNAL_PROCESS: | 
|---|
| 753 | return data.process_internal; | 
|---|
| 754 | case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: | 
|---|
| 755 | return data.physics_process_internal; | 
|---|
| 756 | } | 
|---|
| 757 |  | 
|---|
| 758 | return true; | 
|---|
| 759 | } | 
|---|
| 760 |  | 
|---|
| 761 | bool Node::can_process() const { | 
|---|
| 762 | ERR_FAIL_COND_V(!is_inside_tree(), false); | 
|---|
| 763 | return _can_process(get_tree()->is_paused()); | 
|---|
| 764 | } | 
|---|
| 765 |  | 
|---|
| 766 | bool Node::_can_process(bool p_paused) const { | 
|---|
| 767 | ProcessMode process_mode; | 
|---|
| 768 |  | 
|---|
| 769 | if (data.process_mode == PROCESS_MODE_INHERIT) { | 
|---|
| 770 | if (!data.process_owner) { | 
|---|
| 771 | process_mode = PROCESS_MODE_PAUSABLE; | 
|---|
| 772 | } else { | 
|---|
| 773 | process_mode = data.process_owner->data.process_mode; | 
|---|
| 774 | } | 
|---|
| 775 | } else { | 
|---|
| 776 | process_mode = data.process_mode; | 
|---|
| 777 | } | 
|---|
| 778 |  | 
|---|
| 779 | // The owner can't be set to inherit, must be a bug. | 
|---|
| 780 | ERR_FAIL_COND_V(process_mode == PROCESS_MODE_INHERIT, false); | 
|---|
| 781 |  | 
|---|
| 782 | if (process_mode == PROCESS_MODE_DISABLED) { | 
|---|
| 783 | return false; | 
|---|
| 784 | } else if (process_mode == PROCESS_MODE_ALWAYS) { | 
|---|
| 785 | return true; | 
|---|
| 786 | } | 
|---|
| 787 |  | 
|---|
| 788 | if (p_paused) { | 
|---|
| 789 | return process_mode == PROCESS_MODE_WHEN_PAUSED; | 
|---|
| 790 | } else { | 
|---|
| 791 | return process_mode == PROCESS_MODE_PAUSABLE; | 
|---|
| 792 | } | 
|---|
| 793 | } | 
|---|
| 794 |  | 
|---|
| 795 | bool Node::_is_enabled() const { | 
|---|
| 796 | ProcessMode process_mode; | 
|---|
| 797 |  | 
|---|
| 798 | if (data.process_mode == PROCESS_MODE_INHERIT) { | 
|---|
| 799 | if (!data.process_owner) { | 
|---|
| 800 | process_mode = PROCESS_MODE_PAUSABLE; | 
|---|
| 801 | } else { | 
|---|
| 802 | process_mode = data.process_owner->data.process_mode; | 
|---|
| 803 | } | 
|---|
| 804 | } else { | 
|---|
| 805 | process_mode = data.process_mode; | 
|---|
| 806 | } | 
|---|
| 807 |  | 
|---|
| 808 | return (process_mode != PROCESS_MODE_DISABLED); | 
|---|
| 809 | } | 
|---|
| 810 |  | 
|---|
| 811 | bool Node::is_enabled() const { | 
|---|
| 812 | ERR_FAIL_COND_V(!is_inside_tree(), false); | 
|---|
| 813 | return _is_enabled(); | 
|---|
| 814 | } | 
|---|
| 815 |  | 
|---|
| 816 | double Node::get_physics_process_delta_time() const { | 
|---|
| 817 | if (data.tree) { | 
|---|
| 818 | return data.tree->get_physics_process_time(); | 
|---|
| 819 | } else { | 
|---|
| 820 | return 0; | 
|---|
| 821 | } | 
|---|
| 822 | } | 
|---|
| 823 |  | 
|---|
| 824 | double Node::get_process_delta_time() const { | 
|---|
| 825 | if (data.tree) { | 
|---|
| 826 | return data.tree->get_process_time(); | 
|---|
| 827 | } else { | 
|---|
| 828 | return 0; | 
|---|
| 829 | } | 
|---|
| 830 | } | 
|---|
| 831 |  | 
|---|
| 832 | void Node::set_process(bool p_process) { | 
|---|
| 833 | ERR_THREAD_GUARD | 
|---|
| 834 | if (data.process == p_process) { | 
|---|
| 835 | return; | 
|---|
| 836 | } | 
|---|
| 837 |  | 
|---|
| 838 | if (!is_inside_tree()) { | 
|---|
| 839 | data.process = p_process; | 
|---|
| 840 | return; | 
|---|
| 841 | } | 
|---|
| 842 |  | 
|---|
| 843 | if (_is_any_processing()) { | 
|---|
| 844 | _remove_from_process_thread_group(); | 
|---|
| 845 | } | 
|---|
| 846 |  | 
|---|
| 847 | data.process = p_process; | 
|---|
| 848 |  | 
|---|
| 849 | if (_is_any_processing()) { | 
|---|
| 850 | _add_to_process_thread_group(); | 
|---|
| 851 | } | 
|---|
| 852 | } | 
|---|
| 853 |  | 
|---|
| 854 | bool Node::is_processing() const { | 
|---|
| 855 | return data.process; | 
|---|
| 856 | } | 
|---|
| 857 |  | 
|---|
| 858 | void Node::set_process_internal(bool p_process_internal) { | 
|---|
| 859 | ERR_THREAD_GUARD | 
|---|
| 860 | if (data.process_internal == p_process_internal) { | 
|---|
| 861 | return; | 
|---|
| 862 | } | 
|---|
| 863 |  | 
|---|
| 864 | if (!is_inside_tree()) { | 
|---|
| 865 | data.process_internal = p_process_internal; | 
|---|
| 866 | return; | 
|---|
| 867 | } | 
|---|
| 868 |  | 
|---|
| 869 | if (_is_any_processing()) { | 
|---|
| 870 | _remove_from_process_thread_group(); | 
|---|
| 871 | } | 
|---|
| 872 |  | 
|---|
| 873 | data.process_internal = p_process_internal; | 
|---|
| 874 |  | 
|---|
| 875 | if (_is_any_processing()) { | 
|---|
| 876 | _add_to_process_thread_group(); | 
|---|
| 877 | } | 
|---|
| 878 | } | 
|---|
| 879 |  | 
|---|
| 880 | void Node::_add_process_group() { | 
|---|
| 881 | get_tree()->_add_process_group(this); | 
|---|
| 882 | } | 
|---|
| 883 |  | 
|---|
| 884 | void Node::_remove_process_group() { | 
|---|
| 885 | get_tree()->_remove_process_group(this); | 
|---|
| 886 | } | 
|---|
| 887 |  | 
|---|
| 888 | void Node::_remove_from_process_thread_group() { | 
|---|
| 889 | get_tree()->_remove_node_from_process_group(this, data.process_thread_group_owner); | 
|---|
| 890 | } | 
|---|
| 891 |  | 
|---|
| 892 | void Node::_add_to_process_thread_group() { | 
|---|
| 893 | get_tree()->_add_node_to_process_group(this, data.process_thread_group_owner); | 
|---|
| 894 | } | 
|---|
| 895 |  | 
|---|
| 896 | void Node::_remove_tree_from_process_thread_group() { | 
|---|
| 897 | if (!is_inside_tree()) { | 
|---|
| 898 | return; // May not be initialized yet. | 
|---|
| 899 | } | 
|---|
| 900 |  | 
|---|
| 901 | for (KeyValue<StringName, Node *> &K : data.children) { | 
|---|
| 902 | if (K.value->data.process_thread_group != PROCESS_THREAD_GROUP_INHERIT) { | 
|---|
| 903 | continue; | 
|---|
| 904 | } | 
|---|
| 905 |  | 
|---|
| 906 | K.value->_remove_tree_from_process_thread_group(); | 
|---|
| 907 | } | 
|---|
| 908 |  | 
|---|
| 909 | if (_is_any_processing()) { | 
|---|
| 910 | _remove_from_process_thread_group(); | 
|---|
| 911 | } | 
|---|
| 912 | } | 
|---|
| 913 |  | 
|---|
| 914 | void Node::_add_tree_to_process_thread_group(Node *p_owner) { | 
|---|
| 915 | if (_is_any_processing()) { | 
|---|
| 916 | _add_to_process_thread_group(); | 
|---|
| 917 | } | 
|---|
| 918 |  | 
|---|
| 919 | data.process_thread_group_owner = p_owner; | 
|---|
| 920 | if (p_owner != nullptr) { | 
|---|
| 921 | data.process_group = p_owner->data.process_group; | 
|---|
| 922 | } else { | 
|---|
| 923 | data.process_group = &data.tree->default_process_group; | 
|---|
| 924 | } | 
|---|
| 925 |  | 
|---|
| 926 | for (KeyValue<StringName, Node *> &K : data.children) { | 
|---|
| 927 | if (K.value->data.process_thread_group != PROCESS_THREAD_GROUP_INHERIT) { | 
|---|
| 928 | continue; | 
|---|
| 929 | } | 
|---|
| 930 |  | 
|---|
| 931 | K.value->_add_to_process_thread_group(); | 
|---|
| 932 | } | 
|---|
| 933 | } | 
|---|
| 934 | bool Node::is_processing_internal() const { | 
|---|
| 935 | return data.process_internal; | 
|---|
| 936 | } | 
|---|
| 937 |  | 
|---|
| 938 | void Node::set_process_thread_group_order(int p_order) { | 
|---|
| 939 | ERR_THREAD_GUARD | 
|---|
| 940 | if (data.process_thread_group_order == p_order) { | 
|---|
| 941 | return; | 
|---|
| 942 | } | 
|---|
| 943 |  | 
|---|
| 944 | data.process_thread_group_order = p_order; | 
|---|
| 945 |  | 
|---|
| 946 | // Not yet in the tree (or not a group owner, in whose case this is pointless but harmless); trivial update. | 
|---|
| 947 | if (!is_inside_tree() || data.process_thread_group_owner != this) { | 
|---|
| 948 | return; | 
|---|
| 949 | } | 
|---|
| 950 |  | 
|---|
| 951 | get_tree()->process_groups_dirty = true; | 
|---|
| 952 | } | 
|---|
| 953 |  | 
|---|
| 954 | int Node::get_process_thread_group_order() const { | 
|---|
| 955 | return data.process_thread_group_order; | 
|---|
| 956 | } | 
|---|
| 957 |  | 
|---|
| 958 | void Node::set_process_priority(int p_priority) { | 
|---|
| 959 | ERR_THREAD_GUARD | 
|---|
| 960 | if (data.process_priority == p_priority) { | 
|---|
| 961 | return; | 
|---|
| 962 | } | 
|---|
| 963 | if (!is_inside_tree()) { | 
|---|
| 964 | // Not yet in the tree; trivial update. | 
|---|
| 965 | data.process_priority = p_priority; | 
|---|
| 966 | return; | 
|---|
| 967 | } | 
|---|
| 968 |  | 
|---|
| 969 | if (_is_any_processing()) { | 
|---|
| 970 | _remove_from_process_thread_group(); | 
|---|
| 971 | data.process_priority = p_priority; | 
|---|
| 972 | _add_to_process_thread_group(); | 
|---|
| 973 | } | 
|---|
| 974 | } | 
|---|
| 975 |  | 
|---|
| 976 | int Node::get_process_priority() const { | 
|---|
| 977 | return data.process_priority; | 
|---|
| 978 | } | 
|---|
| 979 |  | 
|---|
| 980 | void Node::set_physics_process_priority(int p_priority) { | 
|---|
| 981 | ERR_THREAD_GUARD | 
|---|
| 982 | if (data.physics_process_priority == p_priority) { | 
|---|
| 983 | return; | 
|---|
| 984 | } | 
|---|
| 985 | if (!is_inside_tree()) { | 
|---|
| 986 | // Not yet in the tree; trivial update. | 
|---|
| 987 | data.physics_process_priority = p_priority; | 
|---|
| 988 | return; | 
|---|
| 989 | } | 
|---|
| 990 |  | 
|---|
| 991 | if (_is_any_processing()) { | 
|---|
| 992 | _remove_from_process_thread_group(); | 
|---|
| 993 | data.physics_process_priority = p_priority; | 
|---|
| 994 | _add_to_process_thread_group(); | 
|---|
| 995 | } | 
|---|
| 996 | } | 
|---|
| 997 |  | 
|---|
| 998 | int Node::get_physics_process_priority() const { | 
|---|
| 999 | return data.physics_process_priority; | 
|---|
| 1000 | } | 
|---|
| 1001 |  | 
|---|
| 1002 | void Node::set_process_thread_group(ProcessThreadGroup p_mode) { | 
|---|
| 1003 | ERR_FAIL_COND_MSG(data.inside_tree && !Thread::is_main_thread(), "Changing the process thread group can only be done from the main thread. Use call_deferred(\"set_process_thread_group\",mode)."); | 
|---|
| 1004 | if (data.process_thread_group == p_mode) { | 
|---|
| 1005 | return; | 
|---|
| 1006 | } | 
|---|
| 1007 |  | 
|---|
| 1008 | if (!is_inside_tree()) { | 
|---|
| 1009 | // Not yet in the tree; trivial update. | 
|---|
| 1010 | data.process_thread_group = p_mode; | 
|---|
| 1011 | return; | 
|---|
| 1012 | } | 
|---|
| 1013 |  | 
|---|
| 1014 | _remove_tree_from_process_thread_group(); | 
|---|
| 1015 | if (data.process_thread_group != PROCESS_THREAD_GROUP_INHERIT) { | 
|---|
| 1016 | _remove_process_group(); | 
|---|
| 1017 | } | 
|---|
| 1018 |  | 
|---|
| 1019 | data.process_thread_group = p_mode; | 
|---|
| 1020 |  | 
|---|
| 1021 | if (p_mode == PROCESS_THREAD_GROUP_INHERIT) { | 
|---|
| 1022 | if (data.parent) { | 
|---|
| 1023 | data.process_thread_group_owner = data.parent->data.process_thread_group_owner; | 
|---|
| 1024 | } else { | 
|---|
| 1025 | data.process_thread_group_owner = nullptr; | 
|---|
| 1026 | } | 
|---|
| 1027 | } else { | 
|---|
| 1028 | data.process_thread_group_owner = this; | 
|---|
| 1029 | _add_process_group(); | 
|---|
| 1030 | } | 
|---|
| 1031 |  | 
|---|
| 1032 | _add_tree_to_process_thread_group(data.process_thread_group_owner); | 
|---|
| 1033 |  | 
|---|
| 1034 | notify_property_list_changed(); | 
|---|
| 1035 | } | 
|---|
| 1036 |  | 
|---|
| 1037 | Node::ProcessThreadGroup Node::get_process_thread_group() const { | 
|---|
| 1038 | return data.process_thread_group; | 
|---|
| 1039 | } | 
|---|
| 1040 |  | 
|---|
| 1041 | void Node::set_process_thread_messages(BitField<ProcessThreadMessages> p_flags) { | 
|---|
| 1042 | ERR_THREAD_GUARD | 
|---|
| 1043 | if (data.process_thread_messages == p_flags) { | 
|---|
| 1044 | return; | 
|---|
| 1045 | } | 
|---|
| 1046 |  | 
|---|
| 1047 | data.process_thread_messages = p_flags; | 
|---|
| 1048 | } | 
|---|
| 1049 |  | 
|---|
| 1050 | BitField<Node::ProcessThreadMessages> Node::get_process_thread_messages() const { | 
|---|
| 1051 | return data.process_thread_messages; | 
|---|
| 1052 | } | 
|---|
| 1053 |  | 
|---|
| 1054 | void Node::set_process_input(bool p_enable) { | 
|---|
| 1055 | ERR_THREAD_GUARD | 
|---|
| 1056 | if (p_enable == data.input) { | 
|---|
| 1057 | return; | 
|---|
| 1058 | } | 
|---|
| 1059 |  | 
|---|
| 1060 | data.input = p_enable; | 
|---|
| 1061 | if (!is_inside_tree()) { | 
|---|
| 1062 | return; | 
|---|
| 1063 | } | 
|---|
| 1064 |  | 
|---|
| 1065 | if (p_enable) { | 
|---|
| 1066 | add_to_group( "_vp_input"+ itos(get_viewport()->get_instance_id())); | 
|---|
| 1067 | } else { | 
|---|
| 1068 | remove_from_group( "_vp_input"+ itos(get_viewport()->get_instance_id())); | 
|---|
| 1069 | } | 
|---|
| 1070 | } | 
|---|
| 1071 |  | 
|---|
| 1072 | bool Node::is_processing_input() const { | 
|---|
| 1073 | return data.input; | 
|---|
| 1074 | } | 
|---|
| 1075 |  | 
|---|
| 1076 | void Node::set_process_shortcut_input(bool p_enable) { | 
|---|
| 1077 | ERR_THREAD_GUARD | 
|---|
| 1078 | if (p_enable == data.shortcut_input) { | 
|---|
| 1079 | return; | 
|---|
| 1080 | } | 
|---|
| 1081 | data.shortcut_input = p_enable; | 
|---|
| 1082 | if (!is_inside_tree()) { | 
|---|
| 1083 | return; | 
|---|
| 1084 | } | 
|---|
| 1085 |  | 
|---|
| 1086 | if (p_enable) { | 
|---|
| 1087 | add_to_group( "_vp_shortcut_input"+ itos(get_viewport()->get_instance_id())); | 
|---|
| 1088 | } else { | 
|---|
| 1089 | remove_from_group( "_vp_shortcut_input"+ itos(get_viewport()->get_instance_id())); | 
|---|
| 1090 | } | 
|---|
| 1091 | } | 
|---|
| 1092 |  | 
|---|
| 1093 | bool Node::is_processing_shortcut_input() const { | 
|---|
| 1094 | return data.shortcut_input; | 
|---|
| 1095 | } | 
|---|
| 1096 |  | 
|---|
| 1097 | void Node::set_process_unhandled_input(bool p_enable) { | 
|---|
| 1098 | ERR_THREAD_GUARD | 
|---|
| 1099 | if (p_enable == data.unhandled_input) { | 
|---|
| 1100 | return; | 
|---|
| 1101 | } | 
|---|
| 1102 | data.unhandled_input = p_enable; | 
|---|
| 1103 | if (!is_inside_tree()) { | 
|---|
| 1104 | return; | 
|---|
| 1105 | } | 
|---|
| 1106 |  | 
|---|
| 1107 | if (p_enable) { | 
|---|
| 1108 | add_to_group( "_vp_unhandled_input"+ itos(get_viewport()->get_instance_id())); | 
|---|
| 1109 | } else { | 
|---|
| 1110 | remove_from_group( "_vp_unhandled_input"+ itos(get_viewport()->get_instance_id())); | 
|---|
| 1111 | } | 
|---|
| 1112 | } | 
|---|
| 1113 |  | 
|---|
| 1114 | bool Node::is_processing_unhandled_input() const { | 
|---|
| 1115 | return data.unhandled_input; | 
|---|
| 1116 | } | 
|---|
| 1117 |  | 
|---|
| 1118 | void Node::set_process_unhandled_key_input(bool p_enable) { | 
|---|
| 1119 | ERR_THREAD_GUARD | 
|---|
| 1120 | if (p_enable == data.unhandled_key_input) { | 
|---|
| 1121 | return; | 
|---|
| 1122 | } | 
|---|
| 1123 | data.unhandled_key_input = p_enable; | 
|---|
| 1124 | if (!is_inside_tree()) { | 
|---|
| 1125 | return; | 
|---|
| 1126 | } | 
|---|
| 1127 |  | 
|---|
| 1128 | if (p_enable) { | 
|---|
| 1129 | add_to_group( "_vp_unhandled_key_input"+ itos(get_viewport()->get_instance_id())); | 
|---|
| 1130 | } else { | 
|---|
| 1131 | remove_from_group( "_vp_unhandled_key_input"+ itos(get_viewport()->get_instance_id())); | 
|---|
| 1132 | } | 
|---|
| 1133 | } | 
|---|
| 1134 |  | 
|---|
| 1135 | bool Node::is_processing_unhandled_key_input() const { | 
|---|
| 1136 | return data.unhandled_key_input; | 
|---|
| 1137 | } | 
|---|
| 1138 |  | 
|---|
| 1139 | StringName Node::get_name() const { | 
|---|
| 1140 | return data.name; | 
|---|
| 1141 | } | 
|---|
| 1142 |  | 
|---|
| 1143 | void Node::_set_name_nocheck(const StringName &p_name) { | 
|---|
| 1144 | data.name = p_name; | 
|---|
| 1145 | } | 
|---|
| 1146 |  | 
|---|
| 1147 | void Node::set_name(const String &p_name) { | 
|---|
| 1148 | ERR_FAIL_COND_MSG(data.inside_tree && !Thread::is_main_thread(), "Changing the name to nodes inside the SceneTree is only allowed from the main thread. Use `set_name.call_deferred(new_name)`."); | 
|---|
| 1149 | String name = p_name.validate_node_name(); | 
|---|
| 1150 |  | 
|---|
| 1151 | ERR_FAIL_COND(name.is_empty()); | 
|---|
| 1152 |  | 
|---|
| 1153 | if (data.unique_name_in_owner && data.owner) { | 
|---|
| 1154 | _release_unique_name_in_owner(); | 
|---|
| 1155 | } | 
|---|
| 1156 | String old_name = data.name; | 
|---|
| 1157 | data.name = name; | 
|---|
| 1158 |  | 
|---|
| 1159 | if (data.parent) { | 
|---|
| 1160 | data.parent->_validate_child_name(this, true); | 
|---|
| 1161 | bool success = data.parent->data.children.replace_key(old_name, data.name); | 
|---|
| 1162 | ERR_FAIL_COND_MSG(!success, "Renaming child in hashtable failed, this is a bug."); | 
|---|
| 1163 | } | 
|---|
| 1164 |  | 
|---|
| 1165 | if (data.unique_name_in_owner && data.owner) { | 
|---|
| 1166 | _acquire_unique_name_in_owner(); | 
|---|
| 1167 | } | 
|---|
| 1168 |  | 
|---|
| 1169 | propagate_notification(NOTIFICATION_PATH_RENAMED); | 
|---|
| 1170 |  | 
|---|
| 1171 | if (is_inside_tree()) { | 
|---|
| 1172 | emit_signal(SNAME( "renamed")); | 
|---|
| 1173 | get_tree()->node_renamed(this); | 
|---|
| 1174 | get_tree()->tree_changed(); | 
|---|
| 1175 | } | 
|---|
| 1176 | } | 
|---|
| 1177 |  | 
|---|
| 1178 | // Returns a clear description of this node depending on what is available. Useful for error messages. | 
|---|
| 1179 | String Node::get_description() const { | 
|---|
| 1180 | String description; | 
|---|
| 1181 | if (is_inside_tree()) { | 
|---|
| 1182 | description = get_path(); | 
|---|
| 1183 | } else { | 
|---|
| 1184 | description = get_name(); | 
|---|
| 1185 | if (description.is_empty()) { | 
|---|
| 1186 | description = get_class(); | 
|---|
| 1187 | } | 
|---|
| 1188 | } | 
|---|
| 1189 | return description; | 
|---|
| 1190 | } | 
|---|
| 1191 |  | 
|---|
| 1192 | static SafeRefCount node_hrcr_count; | 
|---|
| 1193 |  | 
|---|
| 1194 | void Node::init_node_hrcr() { | 
|---|
| 1195 | node_hrcr_count.init(1); | 
|---|
| 1196 | } | 
|---|
| 1197 |  | 
|---|
| 1198 | #ifdef TOOLS_ENABLED | 
|---|
| 1199 | String Node::validate_child_name(Node *p_child) { | 
|---|
| 1200 | StringName name = p_child->data.name; | 
|---|
| 1201 | _generate_serial_child_name(p_child, name); | 
|---|
| 1202 | return name; | 
|---|
| 1203 | } | 
|---|
| 1204 | #endif | 
|---|
| 1205 |  | 
|---|
| 1206 | String Node::adjust_name_casing(const String &p_name) { | 
|---|
| 1207 | switch (GLOBAL_GET( "editor/naming/node_name_casing").operator int()) { | 
|---|
| 1208 | case NAME_CASING_PASCAL_CASE: | 
|---|
| 1209 | return p_name.to_pascal_case(); | 
|---|
| 1210 | case NAME_CASING_CAMEL_CASE: | 
|---|
| 1211 | return p_name.to_camel_case(); | 
|---|
| 1212 | case NAME_CASING_SNAKE_CASE: | 
|---|
| 1213 | return p_name.to_snake_case(); | 
|---|
| 1214 | } | 
|---|
| 1215 | return p_name; | 
|---|
| 1216 | } | 
|---|
| 1217 |  | 
|---|
| 1218 | void Node::_validate_child_name(Node *p_child, bool p_force_human_readable) { | 
|---|
| 1219 | /* Make sure the name is unique */ | 
|---|
| 1220 |  | 
|---|
| 1221 | if (p_force_human_readable) { | 
|---|
| 1222 | //this approach to autoset node names is human readable but very slow | 
|---|
| 1223 |  | 
|---|
| 1224 | StringName name = p_child->data.name; | 
|---|
| 1225 | _generate_serial_child_name(p_child, name); | 
|---|
| 1226 | p_child->data.name = name; | 
|---|
| 1227 |  | 
|---|
| 1228 | } else { | 
|---|
| 1229 | //this approach to autoset node names is fast but not as readable | 
|---|
| 1230 | //it's the default and reserves the '@' character for unique names. | 
|---|
| 1231 |  | 
|---|
| 1232 | bool unique = true; | 
|---|
| 1233 |  | 
|---|
| 1234 | if (p_child->data.name == StringName()) { | 
|---|
| 1235 | //new unique name must be assigned | 
|---|
| 1236 | unique = false; | 
|---|
| 1237 | } else { | 
|---|
| 1238 | const Node *const *existing = data.children.getptr(p_child->data.name); | 
|---|
| 1239 | unique = !existing || *existing == p_child; | 
|---|
| 1240 | } | 
|---|
| 1241 |  | 
|---|
| 1242 | if (!unique) { | 
|---|
| 1243 | ERR_FAIL_COND(!node_hrcr_count.ref()); | 
|---|
| 1244 | // Optimized version of the code below: | 
|---|
| 1245 | // String name = "@" + String(p_child->get_name()) + "@" + itos(node_hrcr_count.get()); | 
|---|
| 1246 | uint32_t c = node_hrcr_count.get(); | 
|---|
| 1247 | String cn = p_child->get_class_name().operator String(); | 
|---|
| 1248 | const char32_t *cn_ptr = cn.ptr(); | 
|---|
| 1249 | uint32_t cn_length = cn.length(); | 
|---|
| 1250 | uint32_t c_chars = String::num_characters(c); | 
|---|
| 1251 | uint32_t len = 2 + cn_length + c_chars; | 
|---|
| 1252 | char32_t *str = (char32_t *)alloca(sizeof(char32_t) * (len + 1)); | 
|---|
| 1253 | uint32_t idx = 0; | 
|---|
| 1254 | str[idx++] = '@'; | 
|---|
| 1255 | for (uint32_t i = 0; i < cn_length; i++) { | 
|---|
| 1256 | str[idx++] = cn_ptr[i]; | 
|---|
| 1257 | } | 
|---|
| 1258 | str[idx++] = '@'; | 
|---|
| 1259 | idx += c_chars; | 
|---|
| 1260 | ERR_FAIL_COND(idx != len); | 
|---|
| 1261 | str[idx] = 0; | 
|---|
| 1262 | while (c) { | 
|---|
| 1263 | str[--idx] = '0' + (c % 10); | 
|---|
| 1264 | c /= 10; | 
|---|
| 1265 | } | 
|---|
| 1266 | p_child->data.name = String(str); | 
|---|
| 1267 | } | 
|---|
| 1268 | } | 
|---|
| 1269 | } | 
|---|
| 1270 |  | 
|---|
| 1271 | // Return s + 1 as if it were an integer | 
|---|
| 1272 | String increase_numeric_string(const String &s) { | 
|---|
| 1273 | String res = s; | 
|---|
| 1274 | bool carry = res.length() > 0; | 
|---|
| 1275 |  | 
|---|
| 1276 | for (int i = res.length() - 1; i >= 0; i--) { | 
|---|
| 1277 | if (!carry) { | 
|---|
| 1278 | break; | 
|---|
| 1279 | } | 
|---|
| 1280 | char32_t n = s[i]; | 
|---|
| 1281 | if (n == '9') { // keep carry as true: 9 + 1 | 
|---|
| 1282 | res[i] = '0'; | 
|---|
| 1283 | } else { | 
|---|
| 1284 | res[i] = s[i] + 1; | 
|---|
| 1285 | carry = false; | 
|---|
| 1286 | } | 
|---|
| 1287 | } | 
|---|
| 1288 |  | 
|---|
| 1289 | if (carry) { | 
|---|
| 1290 | res = "1"+ res; | 
|---|
| 1291 | } | 
|---|
| 1292 |  | 
|---|
| 1293 | return res; | 
|---|
| 1294 | } | 
|---|
| 1295 |  | 
|---|
| 1296 | void Node::_generate_serial_child_name(const Node *p_child, StringName &name) const { | 
|---|
| 1297 | if (name == StringName()) { | 
|---|
| 1298 | // No name and a new name is needed, create one. | 
|---|
| 1299 |  | 
|---|
| 1300 | name = p_child->get_class(); | 
|---|
| 1301 | } | 
|---|
| 1302 |  | 
|---|
| 1303 | const Node *const *existing = data.children.getptr(name); | 
|---|
| 1304 | if (!existing || *existing == p_child) { // Unused, or is current node. | 
|---|
| 1305 | return; | 
|---|
| 1306 | } | 
|---|
| 1307 |  | 
|---|
| 1308 | // Extract trailing number | 
|---|
| 1309 | String name_string = name; | 
|---|
| 1310 | String nums; | 
|---|
| 1311 | for (int i = name_string.length() - 1; i >= 0; i--) { | 
|---|
| 1312 | char32_t n = name_string[i]; | 
|---|
| 1313 | if (is_digit(n)) { | 
|---|
| 1314 | nums = String::chr(name_string[i]) + nums; | 
|---|
| 1315 | } else { | 
|---|
| 1316 | break; | 
|---|
| 1317 | } | 
|---|
| 1318 | } | 
|---|
| 1319 |  | 
|---|
| 1320 | String nnsep = _get_name_num_separator(); | 
|---|
| 1321 | int name_last_index = name_string.length() - nnsep.length() - nums.length(); | 
|---|
| 1322 |  | 
|---|
| 1323 | // Assign the base name + separator to name if we have numbers preceded by a separator | 
|---|
| 1324 | if (nums.length() > 0 && name_string.substr(name_last_index, nnsep.length()) == nnsep) { | 
|---|
| 1325 | name_string = name_string.substr(0, name_last_index + nnsep.length()); | 
|---|
| 1326 | } else { | 
|---|
| 1327 | nums = ""; | 
|---|
| 1328 | } | 
|---|
| 1329 |  | 
|---|
| 1330 | for (;;) { | 
|---|
| 1331 | StringName attempt = name_string + nums; | 
|---|
| 1332 |  | 
|---|
| 1333 | existing = data.children.getptr(attempt); | 
|---|
| 1334 | bool exists = existing != nullptr && *existing != p_child; | 
|---|
| 1335 |  | 
|---|
| 1336 | if (!exists) { | 
|---|
| 1337 | name = attempt; | 
|---|
| 1338 | return; | 
|---|
| 1339 | } else { | 
|---|
| 1340 | if (nums.length() == 0) { | 
|---|
| 1341 | // Name was undecorated so skip to 2 for a more natural result | 
|---|
| 1342 | nums = "2"; | 
|---|
| 1343 | name_string += nnsep; // Add separator because nums.length() > 0 was false | 
|---|
| 1344 | } else { | 
|---|
| 1345 | nums = increase_numeric_string(nums); | 
|---|
| 1346 | } | 
|---|
| 1347 | } | 
|---|
| 1348 | } | 
|---|
| 1349 | } | 
|---|
| 1350 |  | 
|---|
| 1351 | Node::InternalMode Node::get_internal_mode() const { | 
|---|
| 1352 | return data.internal_mode; | 
|---|
| 1353 | } | 
|---|
| 1354 |  | 
|---|
| 1355 | void Node::_add_child_nocheck(Node *p_child, const StringName &p_name, InternalMode p_internal_mode) { | 
|---|
| 1356 | //add a child node quickly, without name validation | 
|---|
| 1357 |  | 
|---|
| 1358 | p_child->data.name = p_name; | 
|---|
| 1359 | data.children.insert(p_name, p_child); | 
|---|
| 1360 |  | 
|---|
| 1361 | p_child->data.internal_mode = p_internal_mode; | 
|---|
| 1362 | switch (p_internal_mode) { | 
|---|
| 1363 | case INTERNAL_MODE_FRONT: { | 
|---|
| 1364 | p_child->data.index = data.internal_children_front_count_cache++; | 
|---|
| 1365 | } break; | 
|---|
| 1366 | case INTERNAL_MODE_BACK: { | 
|---|
| 1367 | p_child->data.index = data.internal_children_back_count_cache++; | 
|---|
| 1368 | } break; | 
|---|
| 1369 | case INTERNAL_MODE_DISABLED: { | 
|---|
| 1370 | p_child->data.index = data.external_children_count_cache++; | 
|---|
| 1371 | } break; | 
|---|
| 1372 | } | 
|---|
| 1373 |  | 
|---|
| 1374 | p_child->data.parent = this; | 
|---|
| 1375 |  | 
|---|
| 1376 | if (!data.children_cache_dirty && p_internal_mode == INTERNAL_MODE_DISABLED && data.internal_children_back_count_cache == 0) { | 
|---|
| 1377 | // Special case, also add to the cached children array since its cheap. | 
|---|
| 1378 | data.children_cache.push_back(p_child); | 
|---|
| 1379 | } else { | 
|---|
| 1380 | data.children_cache_dirty = true; | 
|---|
| 1381 | } | 
|---|
| 1382 |  | 
|---|
| 1383 | p_child->notification(NOTIFICATION_PARENTED); | 
|---|
| 1384 |  | 
|---|
| 1385 | if (data.tree) { | 
|---|
| 1386 | p_child->_set_tree(data.tree); | 
|---|
| 1387 | } | 
|---|
| 1388 |  | 
|---|
| 1389 | /* Notify */ | 
|---|
| 1390 | //recognize children created in this node constructor | 
|---|
| 1391 | p_child->data.parent_owned = data.in_constructor; | 
|---|
| 1392 | add_child_notify(p_child); | 
|---|
| 1393 | notification(NOTIFICATION_CHILD_ORDER_CHANGED); | 
|---|
| 1394 | emit_signal(SNAME( "child_order_changed")); | 
|---|
| 1395 | } | 
|---|
| 1396 |  | 
|---|
| 1397 | void Node::add_child(Node *p_child, bool p_force_readable_name, InternalMode p_internal) { | 
|---|
| 1398 | ERR_FAIL_COND_MSG(data.inside_tree && !Thread::is_main_thread(), "Adding children to a node inside the SceneTree is only allowed from the main thread. Use call_deferred(\"add_child\",node)."); | 
|---|
| 1399 |  | 
|---|
| 1400 | ERR_THREAD_GUARD | 
|---|
| 1401 | ERR_FAIL_NULL(p_child); | 
|---|
| 1402 | ERR_FAIL_COND_MSG(p_child == this, vformat( "Can't add child '%s' to itself.", p_child->get_name())); // adding to itself! | 
|---|
| 1403 | ERR_FAIL_COND_MSG(p_child->data.parent, vformat( "Can't add child '%s' to '%s', already has a parent '%s'.", p_child->get_name(), get_name(), p_child->data.parent->get_name())); //Fail if node has a parent | 
|---|
| 1404 | #ifdef DEBUG_ENABLED | 
|---|
| 1405 | ERR_FAIL_COND_MSG(p_child->is_ancestor_of(this), vformat( "Can't add child '%s' to '%s' as it would result in a cyclic dependency since '%s' is already a parent of '%s'.", p_child->get_name(), get_name(), p_child->get_name(), get_name())); | 
|---|
| 1406 | #endif | 
|---|
| 1407 | 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."); | 
|---|
| 1408 |  | 
|---|
| 1409 | _validate_child_name(p_child, p_force_readable_name); | 
|---|
| 1410 | _add_child_nocheck(p_child, p_child->data.name, p_internal); | 
|---|
| 1411 | } | 
|---|
| 1412 |  | 
|---|
| 1413 | void Node::add_sibling(Node *p_sibling, bool p_force_readable_name) { | 
|---|
| 1414 | ERR_FAIL_COND_MSG(data.inside_tree && !Thread::is_main_thread(), "Adding a sibling to a node inside the SceneTree is only allowed from the main thread. Use call_deferred(\"add_sibling\",node)."); | 
|---|
| 1415 | ERR_FAIL_NULL(p_sibling); | 
|---|
| 1416 | ERR_FAIL_COND_MSG(p_sibling == this, vformat( "Can't add sibling '%s' to itself.", p_sibling->get_name())); // adding to itself! | 
|---|
| 1417 | ERR_FAIL_NULL(data.parent); | 
|---|
| 1418 | ERR_FAIL_COND_MSG(data.parent->data.blocked > 0, "Parent node is busy setting up children, `add_sibling()` failed. Consider using `add_sibling.call_deferred(sibling)` instead."); | 
|---|
| 1419 |  | 
|---|
| 1420 | data.parent->add_child(p_sibling, p_force_readable_name, data.internal_mode); | 
|---|
| 1421 | data.parent->_update_children_cache(); | 
|---|
| 1422 | data.parent->_move_child(p_sibling, get_index() + 1); | 
|---|
| 1423 | } | 
|---|
| 1424 |  | 
|---|
| 1425 | void Node::remove_child(Node *p_child) { | 
|---|
| 1426 | ERR_FAIL_COND_MSG(data.inside_tree && !Thread::is_main_thread(), "Removing children from a node inside the SceneTree is only allowed from the main thread. Use call_deferred(\"remove_child\",node)."); | 
|---|
| 1427 | ERR_FAIL_NULL(p_child); | 
|---|
| 1428 | 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."); | 
|---|
| 1429 | ERR_FAIL_COND(p_child->data.parent != this); | 
|---|
| 1430 |  | 
|---|
| 1431 | /** | 
|---|
| 1432 | *  Do not change the data.internal_children*cache counters here. | 
|---|
| 1433 | *  Because if nodes are re-added, the indices can remain | 
|---|
| 1434 | *  greater-than-everything indices and children added remain | 
|---|
| 1435 | *  properly ordered. | 
|---|
| 1436 | * | 
|---|
| 1437 | *  All children indices and counters will be updated next time the | 
|---|
| 1438 | *  cache is re-generated. | 
|---|
| 1439 | */ | 
|---|
| 1440 |  | 
|---|
| 1441 | data.blocked++; | 
|---|
| 1442 | p_child->_set_tree(nullptr); | 
|---|
| 1443 | //} | 
|---|
| 1444 |  | 
|---|
| 1445 | remove_child_notify(p_child); | 
|---|
| 1446 | p_child->notification(NOTIFICATION_UNPARENTED); | 
|---|
| 1447 |  | 
|---|
| 1448 | data.blocked--; | 
|---|
| 1449 |  | 
|---|
| 1450 | data.children_cache_dirty = true; | 
|---|
| 1451 | bool success = data.children.erase(p_child->data.name); | 
|---|
| 1452 | ERR_FAIL_COND_MSG(!success, "Children name does not match parent name in hashtable, this is a bug."); | 
|---|
| 1453 |  | 
|---|
| 1454 | p_child->data.parent = nullptr; | 
|---|
| 1455 | p_child->data.index = -1; | 
|---|
| 1456 |  | 
|---|
| 1457 | notification(NOTIFICATION_CHILD_ORDER_CHANGED); | 
|---|
| 1458 | emit_signal(SNAME( "child_order_changed")); | 
|---|
| 1459 |  | 
|---|
| 1460 | if (data.inside_tree) { | 
|---|
| 1461 | p_child->_propagate_after_exit_tree(); | 
|---|
| 1462 | } | 
|---|
| 1463 | } | 
|---|
| 1464 |  | 
|---|
| 1465 | void Node::_update_children_cache_impl() const { | 
|---|
| 1466 | // Assign children | 
|---|
| 1467 | data.children_cache.resize(data.children.size()); | 
|---|
| 1468 | int idx = 0; | 
|---|
| 1469 | for (const KeyValue<StringName, Node *> &K : data.children) { | 
|---|
| 1470 | data.children_cache[idx] = K.value; | 
|---|
| 1471 | idx++; | 
|---|
| 1472 | } | 
|---|
| 1473 | // Sort them | 
|---|
| 1474 | data.children_cache.sort_custom<ComparatorByIndex>(); | 
|---|
| 1475 | // Update indices | 
|---|
| 1476 | data.external_children_count_cache = 0; | 
|---|
| 1477 | data.internal_children_back_count_cache = 0; | 
|---|
| 1478 | data.internal_children_front_count_cache = 0; | 
|---|
| 1479 |  | 
|---|
| 1480 | for (uint32_t i = 0; i < data.children_cache.size(); i++) { | 
|---|
| 1481 | switch (data.children_cache[i]->data.internal_mode) { | 
|---|
| 1482 | case INTERNAL_MODE_DISABLED: { | 
|---|
| 1483 | data.children_cache[i]->data.index = data.external_children_count_cache++; | 
|---|
| 1484 | } break; | 
|---|
| 1485 | case INTERNAL_MODE_FRONT: { | 
|---|
| 1486 | data.children_cache[i]->data.index = data.internal_children_front_count_cache++; | 
|---|
| 1487 | } break; | 
|---|
| 1488 | case INTERNAL_MODE_BACK: { | 
|---|
| 1489 | data.children_cache[i]->data.index = data.internal_children_back_count_cache++; | 
|---|
| 1490 | } break; | 
|---|
| 1491 | } | 
|---|
| 1492 | } | 
|---|
| 1493 | data.children_cache_dirty = false; | 
|---|
| 1494 | } | 
|---|
| 1495 |  | 
|---|
| 1496 | int Node::get_child_count(bool p_include_internal) const { | 
|---|
| 1497 | ERR_THREAD_GUARD_V(0); | 
|---|
| 1498 | _update_children_cache(); | 
|---|
| 1499 |  | 
|---|
| 1500 | if (p_include_internal) { | 
|---|
| 1501 | return data.children_cache.size(); | 
|---|
| 1502 | } else { | 
|---|
| 1503 | return data.children_cache.size() - data.internal_children_front_count_cache - data.internal_children_back_count_cache; | 
|---|
| 1504 | } | 
|---|
| 1505 | } | 
|---|
| 1506 |  | 
|---|
| 1507 | Node *Node::get_child(int p_index, bool p_include_internal) const { | 
|---|
| 1508 | ERR_THREAD_GUARD_V(nullptr); | 
|---|
| 1509 | _update_children_cache(); | 
|---|
| 1510 |  | 
|---|
| 1511 | if (p_include_internal) { | 
|---|
| 1512 | if (p_index < 0) { | 
|---|
| 1513 | p_index += data.children_cache.size(); | 
|---|
| 1514 | } | 
|---|
| 1515 | ERR_FAIL_INDEX_V(p_index, (int)data.children_cache.size(), nullptr); | 
|---|
| 1516 | return data.children_cache[p_index]; | 
|---|
| 1517 | } else { | 
|---|
| 1518 | if (p_index < 0) { | 
|---|
| 1519 | p_index += (int)data.children_cache.size() - data.internal_children_front_count_cache - data.internal_children_back_count_cache; | 
|---|
| 1520 | } | 
|---|
| 1521 | ERR_FAIL_INDEX_V(p_index, (int)data.children_cache.size() - data.internal_children_front_count_cache - data.internal_children_back_count_cache, nullptr); | 
|---|
| 1522 | p_index += data.internal_children_front_count_cache; | 
|---|
| 1523 | return data.children_cache[p_index]; | 
|---|
| 1524 | } | 
|---|
| 1525 | } | 
|---|
| 1526 |  | 
|---|
| 1527 | TypedArray<Node> Node::get_children(bool p_include_internal) const { | 
|---|
| 1528 | ERR_THREAD_GUARD_V(TypedArray<Node>()); | 
|---|
| 1529 | TypedArray<Node> arr; | 
|---|
| 1530 | int cc = get_child_count(p_include_internal); | 
|---|
| 1531 | arr.resize(cc); | 
|---|
| 1532 | for (int i = 0; i < cc; i++) { | 
|---|
| 1533 | arr[i] = get_child(i, p_include_internal); | 
|---|
| 1534 | } | 
|---|
| 1535 |  | 
|---|
| 1536 | return arr; | 
|---|
| 1537 | } | 
|---|
| 1538 |  | 
|---|
| 1539 | Node *Node::_get_child_by_name(const StringName &p_name) const { | 
|---|
| 1540 | const Node *const *node = data.children.getptr(p_name); | 
|---|
| 1541 | if (node) { | 
|---|
| 1542 | return const_cast<Node *>(*node); | 
|---|
| 1543 | } else { | 
|---|
| 1544 | return nullptr; | 
|---|
| 1545 | } | 
|---|
| 1546 | } | 
|---|
| 1547 |  | 
|---|
| 1548 | Node *Node::get_node_or_null(const NodePath &p_path) const { | 
|---|
| 1549 | ERR_THREAD_GUARD_V(nullptr); | 
|---|
| 1550 | if (p_path.is_empty()) { | 
|---|
| 1551 | return nullptr; | 
|---|
| 1552 | } | 
|---|
| 1553 |  | 
|---|
| 1554 | ERR_FAIL_COND_V_MSG(!data.inside_tree && p_path.is_absolute(), nullptr, "Can't use get_node() with absolute paths from outside the active scene tree."); | 
|---|
| 1555 |  | 
|---|
| 1556 | Node *current = nullptr; | 
|---|
| 1557 | Node *root = nullptr; | 
|---|
| 1558 |  | 
|---|
| 1559 | if (!p_path.is_absolute()) { | 
|---|
| 1560 | current = const_cast<Node *>(this); //start from this | 
|---|
| 1561 | } else { | 
|---|
| 1562 | root = const_cast<Node *>(this); | 
|---|
| 1563 | while (root->data.parent) { | 
|---|
| 1564 | root = root->data.parent; //start from root | 
|---|
| 1565 | } | 
|---|
| 1566 | } | 
|---|
| 1567 |  | 
|---|
| 1568 | for (int i = 0; i < p_path.get_name_count(); i++) { | 
|---|
| 1569 | StringName name = p_path.get_name(i); | 
|---|
| 1570 | Node *next = nullptr; | 
|---|
| 1571 |  | 
|---|
| 1572 | if (name == SceneStringNames::get_singleton()->dot) { // . | 
|---|
| 1573 |  | 
|---|
| 1574 | next = current; | 
|---|
| 1575 |  | 
|---|
| 1576 | } else if (name == SceneStringNames::get_singleton()->doubledot) { // .. | 
|---|
| 1577 |  | 
|---|
| 1578 | if (current == nullptr || !current->data.parent) { | 
|---|
| 1579 | return nullptr; | 
|---|
| 1580 | } | 
|---|
| 1581 |  | 
|---|
| 1582 | next = current->data.parent; | 
|---|
| 1583 | } else if (current == nullptr) { | 
|---|
| 1584 | if (name == root->get_name()) { | 
|---|
| 1585 | next = root; | 
|---|
| 1586 | } | 
|---|
| 1587 |  | 
|---|
| 1588 | } else if (name.is_node_unique_name()) { | 
|---|
| 1589 | if (current->data.owned_unique_nodes.size()) { | 
|---|
| 1590 | // Has unique nodes in ownership | 
|---|
| 1591 | Node **unique = current->data.owned_unique_nodes.getptr(name); | 
|---|
| 1592 | if (!unique) { | 
|---|
| 1593 | return nullptr; | 
|---|
| 1594 | } | 
|---|
| 1595 | next = *unique; | 
|---|
| 1596 | } else if (current->data.owner) { | 
|---|
| 1597 | Node **unique = current->data.owner->data.owned_unique_nodes.getptr(name); | 
|---|
| 1598 | if (!unique) { | 
|---|
| 1599 | return nullptr; | 
|---|
| 1600 | } | 
|---|
| 1601 | next = *unique; | 
|---|
| 1602 | } else { | 
|---|
| 1603 | return nullptr; | 
|---|
| 1604 | } | 
|---|
| 1605 |  | 
|---|
| 1606 | } else { | 
|---|
| 1607 | next = nullptr; | 
|---|
| 1608 | const Node *const *node = current->data.children.getptr(name); | 
|---|
| 1609 | if (node) { | 
|---|
| 1610 | next = const_cast<Node *>(*node); | 
|---|
| 1611 | } else { | 
|---|
| 1612 | return nullptr; | 
|---|
| 1613 | } | 
|---|
| 1614 | } | 
|---|
| 1615 | current = next; | 
|---|
| 1616 | } | 
|---|
| 1617 |  | 
|---|
| 1618 | return current; | 
|---|
| 1619 | } | 
|---|
| 1620 |  | 
|---|
| 1621 | Node *Node::get_node(const NodePath &p_path) const { | 
|---|
| 1622 | Node *node = get_node_or_null(p_path); | 
|---|
| 1623 |  | 
|---|
| 1624 | if (unlikely(!node)) { | 
|---|
| 1625 | const String desc = get_description(); | 
|---|
| 1626 | if (p_path.is_absolute()) { | 
|---|
| 1627 | ERR_FAIL_V_MSG(nullptr, | 
|---|
| 1628 | vformat( R"(Node not found: "%s" (absolute path attempted from "%s").)", p_path, desc)); | 
|---|
| 1629 | } else { | 
|---|
| 1630 | ERR_FAIL_V_MSG(nullptr, | 
|---|
| 1631 | vformat( R"(Node not found: "%s" (relative to "%s").)", p_path, desc)); | 
|---|
| 1632 | } | 
|---|
| 1633 | } | 
|---|
| 1634 |  | 
|---|
| 1635 | return node; | 
|---|
| 1636 | } | 
|---|
| 1637 |  | 
|---|
| 1638 | bool Node::has_node(const NodePath &p_path) const { | 
|---|
| 1639 | return get_node_or_null(p_path) != nullptr; | 
|---|
| 1640 | } | 
|---|
| 1641 |  | 
|---|
| 1642 | // Finds the first child node (in tree order) whose name matches the given pattern. | 
|---|
| 1643 | // Can be recursive or not, and limited to owned nodes. | 
|---|
| 1644 | Node *Node::find_child(const String &p_pattern, bool p_recursive, bool p_owned) const { | 
|---|
| 1645 | ERR_THREAD_GUARD_V(nullptr); | 
|---|
| 1646 | ERR_FAIL_COND_V(p_pattern.is_empty(), nullptr); | 
|---|
| 1647 | _update_children_cache(); | 
|---|
| 1648 | Node *const *cptr = data.children_cache.ptr(); | 
|---|
| 1649 | int ccount = data.children_cache.size(); | 
|---|
| 1650 | for (int i = 0; i < ccount; i++) { | 
|---|
| 1651 | if (p_owned && !cptr[i]->data.owner) { | 
|---|
| 1652 | continue; | 
|---|
| 1653 | } | 
|---|
| 1654 | if (cptr[i]->data.name.operator String().match(p_pattern)) { | 
|---|
| 1655 | return cptr[i]; | 
|---|
| 1656 | } | 
|---|
| 1657 |  | 
|---|
| 1658 | if (!p_recursive) { | 
|---|
| 1659 | continue; | 
|---|
| 1660 | } | 
|---|
| 1661 |  | 
|---|
| 1662 | Node *ret = cptr[i]->find_child(p_pattern, true, p_owned); | 
|---|
| 1663 | if (ret) { | 
|---|
| 1664 | return ret; | 
|---|
| 1665 | } | 
|---|
| 1666 | } | 
|---|
| 1667 | return nullptr; | 
|---|
| 1668 | } | 
|---|
| 1669 |  | 
|---|
| 1670 | // Finds child nodes based on their name using pattern matching, or class name, | 
|---|
| 1671 | // or both (either pattern or type can be left empty). | 
|---|
| 1672 | // Can be recursive or not, and limited to owned nodes. | 
|---|
| 1673 | TypedArray<Node> Node::find_children(const String &p_pattern, const String &p_type, bool p_recursive, bool p_owned) const { | 
|---|
| 1674 | ERR_THREAD_GUARD_V(TypedArray<Node>()); | 
|---|
| 1675 | TypedArray<Node> ret; | 
|---|
| 1676 | ERR_FAIL_COND_V(p_pattern.is_empty() && p_type.is_empty(), ret); | 
|---|
| 1677 | _update_children_cache(); | 
|---|
| 1678 | Node *const *cptr = data.children_cache.ptr(); | 
|---|
| 1679 | int ccount = data.children_cache.size(); | 
|---|
| 1680 | for (int i = 0; i < ccount; i++) { | 
|---|
| 1681 | if (p_owned && !cptr[i]->data.owner) { | 
|---|
| 1682 | continue; | 
|---|
| 1683 | } | 
|---|
| 1684 |  | 
|---|
| 1685 | if (p_pattern.is_empty() || cptr[i]->data.name.operator String().match(p_pattern)) { | 
|---|
| 1686 | if (p_type.is_empty() || cptr[i]->is_class(p_type)) { | 
|---|
| 1687 | ret.append(cptr[i]); | 
|---|
| 1688 | } else if (cptr[i]->get_script_instance()) { | 
|---|
| 1689 | Ref<Script> scr = cptr[i]->get_script_instance()->get_script(); | 
|---|
| 1690 | while (scr.is_valid()) { | 
|---|
| 1691 | if ((ScriptServer::is_global_class(p_type) && ScriptServer::get_global_class_path(p_type) == scr->get_path()) || p_type == scr->get_path()) { | 
|---|
| 1692 | ret.append(cptr[i]); | 
|---|
| 1693 | break; | 
|---|
| 1694 | } | 
|---|
| 1695 |  | 
|---|
| 1696 | scr = scr->get_base_script(); | 
|---|
| 1697 | } | 
|---|
| 1698 | } | 
|---|
| 1699 | } | 
|---|
| 1700 |  | 
|---|
| 1701 | if (p_recursive) { | 
|---|
| 1702 | ret.append_array(cptr[i]->find_children(p_pattern, p_type, true, p_owned)); | 
|---|
| 1703 | } | 
|---|
| 1704 | } | 
|---|
| 1705 |  | 
|---|
| 1706 | return ret; | 
|---|
| 1707 | } | 
|---|
| 1708 |  | 
|---|
| 1709 | void Node::reparent(Node *p_parent, bool p_keep_global_transform) { | 
|---|
| 1710 | ERR_THREAD_GUARD | 
|---|
| 1711 | ERR_FAIL_NULL(p_parent); | 
|---|
| 1712 | ERR_FAIL_NULL_MSG(data.parent, "Node needs a parent to be reparented."); | 
|---|
| 1713 |  | 
|---|
| 1714 | if (p_parent == data.parent) { | 
|---|
| 1715 | return; | 
|---|
| 1716 | } | 
|---|
| 1717 |  | 
|---|
| 1718 | data.parent->remove_child(this); | 
|---|
| 1719 | p_parent->add_child(this); | 
|---|
| 1720 | } | 
|---|
| 1721 |  | 
|---|
| 1722 | Node *Node::get_parent() const { | 
|---|
| 1723 | return data.parent; | 
|---|
| 1724 | } | 
|---|
| 1725 |  | 
|---|
| 1726 | Node *Node::find_parent(const String &p_pattern) const { | 
|---|
| 1727 | ERR_THREAD_GUARD_V(nullptr); | 
|---|
| 1728 | Node *p = data.parent; | 
|---|
| 1729 | while (p) { | 
|---|
| 1730 | if (p->data.name.operator String().match(p_pattern)) { | 
|---|
| 1731 | return p; | 
|---|
| 1732 | } | 
|---|
| 1733 | p = p->data.parent; | 
|---|
| 1734 | } | 
|---|
| 1735 |  | 
|---|
| 1736 | return nullptr; | 
|---|
| 1737 | } | 
|---|
| 1738 |  | 
|---|
| 1739 | Window *Node::get_window() const { | 
|---|
| 1740 | ERR_THREAD_GUARD_V(nullptr); | 
|---|
| 1741 | Viewport *vp = get_viewport(); | 
|---|
| 1742 | if (vp) { | 
|---|
| 1743 | return vp->get_base_window(); | 
|---|
| 1744 | } | 
|---|
| 1745 | return nullptr; | 
|---|
| 1746 | } | 
|---|
| 1747 |  | 
|---|
| 1748 | Window *Node::get_last_exclusive_window() const { | 
|---|
| 1749 | Window *w = get_window(); | 
|---|
| 1750 | while (w && w->get_exclusive_child()) { | 
|---|
| 1751 | w = w->get_exclusive_child(); | 
|---|
| 1752 | } | 
|---|
| 1753 |  | 
|---|
| 1754 | return w; | 
|---|
| 1755 | } | 
|---|
| 1756 |  | 
|---|
| 1757 | bool Node::is_ancestor_of(const Node *p_node) const { | 
|---|
| 1758 | ERR_FAIL_NULL_V(p_node, false); | 
|---|
| 1759 | Node *p = p_node->data.parent; | 
|---|
| 1760 | while (p) { | 
|---|
| 1761 | if (p == this) { | 
|---|
| 1762 | return true; | 
|---|
| 1763 | } | 
|---|
| 1764 | p = p->data.parent; | 
|---|
| 1765 | } | 
|---|
| 1766 |  | 
|---|
| 1767 | return false; | 
|---|
| 1768 | } | 
|---|
| 1769 |  | 
|---|
| 1770 | bool Node::is_greater_than(const Node *p_node) const { | 
|---|
| 1771 | ERR_FAIL_NULL_V(p_node, false); | 
|---|
| 1772 | ERR_FAIL_COND_V(!data.inside_tree, false); | 
|---|
| 1773 | ERR_FAIL_COND_V(!p_node->data.inside_tree, false); | 
|---|
| 1774 |  | 
|---|
| 1775 | ERR_FAIL_COND_V(data.depth < 0, false); | 
|---|
| 1776 | ERR_FAIL_COND_V(p_node->data.depth < 0, false); | 
|---|
| 1777 |  | 
|---|
| 1778 | _update_children_cache(); | 
|---|
| 1779 |  | 
|---|
| 1780 | int *this_stack = (int *)alloca(sizeof(int) * data.depth); | 
|---|
| 1781 | int *that_stack = (int *)alloca(sizeof(int) * p_node->data.depth); | 
|---|
| 1782 |  | 
|---|
| 1783 | const Node *n = this; | 
|---|
| 1784 |  | 
|---|
| 1785 | int idx = data.depth - 1; | 
|---|
| 1786 | while (n) { | 
|---|
| 1787 | ERR_FAIL_INDEX_V(idx, data.depth, false); | 
|---|
| 1788 | this_stack[idx--] = n->get_index(); | 
|---|
| 1789 | n = n->data.parent; | 
|---|
| 1790 | } | 
|---|
| 1791 |  | 
|---|
| 1792 | ERR_FAIL_COND_V(idx != -1, false); | 
|---|
| 1793 | n = p_node; | 
|---|
| 1794 | idx = p_node->data.depth - 1; | 
|---|
| 1795 | while (n) { | 
|---|
| 1796 | ERR_FAIL_INDEX_V(idx, p_node->data.depth, false); | 
|---|
| 1797 | that_stack[idx--] = n->get_index(); | 
|---|
| 1798 |  | 
|---|
| 1799 | n = n->data.parent; | 
|---|
| 1800 | } | 
|---|
| 1801 | ERR_FAIL_COND_V(idx != -1, false); | 
|---|
| 1802 | idx = 0; | 
|---|
| 1803 |  | 
|---|
| 1804 | bool res; | 
|---|
| 1805 | while (true) { | 
|---|
| 1806 | // using -2 since out-of-tree or nonroot nodes have -1 | 
|---|
| 1807 | int this_idx = (idx >= data.depth) ? -2 : this_stack[idx]; | 
|---|
| 1808 | int that_idx = (idx >= p_node->data.depth) ? -2 : that_stack[idx]; | 
|---|
| 1809 |  | 
|---|
| 1810 | if (this_idx > that_idx) { | 
|---|
| 1811 | res = true; | 
|---|
| 1812 | break; | 
|---|
| 1813 | } else if (this_idx < that_idx) { | 
|---|
| 1814 | res = false; | 
|---|
| 1815 | break; | 
|---|
| 1816 | } else if (this_idx == -2) { | 
|---|
| 1817 | res = false; // equal | 
|---|
| 1818 | break; | 
|---|
| 1819 | } | 
|---|
| 1820 | idx++; | 
|---|
| 1821 | } | 
|---|
| 1822 |  | 
|---|
| 1823 | return res; | 
|---|
| 1824 | } | 
|---|
| 1825 |  | 
|---|
| 1826 | void Node::get_owned_by(Node *p_by, List<Node *> *p_owned) { | 
|---|
| 1827 | if (data.owner == p_by) { | 
|---|
| 1828 | p_owned->push_back(this); | 
|---|
| 1829 | } | 
|---|
| 1830 |  | 
|---|
| 1831 | for (KeyValue<StringName, Node *> &K : data.children) { | 
|---|
| 1832 | K.value->get_owned_by(p_by, p_owned); | 
|---|
| 1833 | } | 
|---|
| 1834 | } | 
|---|
| 1835 |  | 
|---|
| 1836 | void Node::_set_owner_nocheck(Node *p_owner) { | 
|---|
| 1837 | if (data.owner == p_owner) { | 
|---|
| 1838 | return; | 
|---|
| 1839 | } | 
|---|
| 1840 |  | 
|---|
| 1841 | ERR_FAIL_COND(data.owner); | 
|---|
| 1842 | data.owner = p_owner; | 
|---|
| 1843 | data.owner->data.owned.push_back(this); | 
|---|
| 1844 | data.OW = data.owner->data.owned.back(); | 
|---|
| 1845 |  | 
|---|
| 1846 | owner_changed_notify(); | 
|---|
| 1847 | } | 
|---|
| 1848 |  | 
|---|
| 1849 | void Node::_release_unique_name_in_owner() { | 
|---|
| 1850 | ERR_FAIL_NULL(data.owner); // Sanity check. | 
|---|
| 1851 | StringName key = StringName(UNIQUE_NODE_PREFIX + data.name.operator String()); | 
|---|
| 1852 | Node **which = data.owner->data.owned_unique_nodes.getptr(key); | 
|---|
| 1853 | if (which == nullptr || *which != this) { | 
|---|
| 1854 | return; // Ignore. | 
|---|
| 1855 | } | 
|---|
| 1856 | data.owner->data.owned_unique_nodes.erase(key); | 
|---|
| 1857 | } | 
|---|
| 1858 |  | 
|---|
| 1859 | void Node::_acquire_unique_name_in_owner() { | 
|---|
| 1860 | ERR_FAIL_NULL(data.owner); // Sanity check. | 
|---|
| 1861 | StringName key = StringName(UNIQUE_NODE_PREFIX + data.name.operator String()); | 
|---|
| 1862 | Node **which = data.owner->data.owned_unique_nodes.getptr(key); | 
|---|
| 1863 | if (which != nullptr && *which != this) { | 
|---|
| 1864 | String which_path = is_inside_tree() ? (*which)->get_path() : data.owner->get_path_to(*which); | 
|---|
| 1865 | WARN_PRINT(vformat(RTR( "Setting node name '%s' to be unique within scene for '%s', but it's already claimed by '%s'.\n'%s' is no longer set as having a unique name."), | 
|---|
| 1866 | get_name(), is_inside_tree() ? get_path() : data.owner->get_path_to(this), which_path, which_path)); | 
|---|
| 1867 | data.unique_name_in_owner = false; | 
|---|
| 1868 | return; | 
|---|
| 1869 | } | 
|---|
| 1870 | data.owner->data.owned_unique_nodes[key] = this; | 
|---|
| 1871 | } | 
|---|
| 1872 |  | 
|---|
| 1873 | void Node::set_unique_name_in_owner(bool p_enabled) { | 
|---|
| 1874 | ERR_MAIN_THREAD_GUARD | 
|---|
| 1875 | if (data.unique_name_in_owner == p_enabled) { | 
|---|
| 1876 | return; | 
|---|
| 1877 | } | 
|---|
| 1878 |  | 
|---|
| 1879 | if (data.unique_name_in_owner && data.owner != nullptr) { | 
|---|
| 1880 | _release_unique_name_in_owner(); | 
|---|
| 1881 | } | 
|---|
| 1882 | data.unique_name_in_owner = p_enabled; | 
|---|
| 1883 |  | 
|---|
| 1884 | if (data.unique_name_in_owner && data.owner != nullptr) { | 
|---|
| 1885 | _acquire_unique_name_in_owner(); | 
|---|
| 1886 | } | 
|---|
| 1887 |  | 
|---|
| 1888 | update_configuration_warnings(); | 
|---|
| 1889 | } | 
|---|
| 1890 |  | 
|---|
| 1891 | bool Node::is_unique_name_in_owner() const { | 
|---|
| 1892 | return data.unique_name_in_owner; | 
|---|
| 1893 | } | 
|---|
| 1894 |  | 
|---|
| 1895 | void Node::set_owner(Node *p_owner) { | 
|---|
| 1896 | ERR_MAIN_THREAD_GUARD | 
|---|
| 1897 | if (data.owner) { | 
|---|
| 1898 | _clean_up_owner(); | 
|---|
| 1899 | } | 
|---|
| 1900 |  | 
|---|
| 1901 | ERR_FAIL_COND(p_owner == this); | 
|---|
| 1902 |  | 
|---|
| 1903 | if (!p_owner) { | 
|---|
| 1904 | return; | 
|---|
| 1905 | } | 
|---|
| 1906 |  | 
|---|
| 1907 | Node *check = this->get_parent(); | 
|---|
| 1908 | bool owner_valid = false; | 
|---|
| 1909 |  | 
|---|
| 1910 | while (check) { | 
|---|
| 1911 | if (check == p_owner) { | 
|---|
| 1912 | owner_valid = true; | 
|---|
| 1913 | break; | 
|---|
| 1914 | } | 
|---|
| 1915 |  | 
|---|
| 1916 | check = check->data.parent; | 
|---|
| 1917 | } | 
|---|
| 1918 |  | 
|---|
| 1919 | ERR_FAIL_COND_MSG(!owner_valid, "Invalid owner. Owner must be an ancestor in the tree."); | 
|---|
| 1920 |  | 
|---|
| 1921 | _set_owner_nocheck(p_owner); | 
|---|
| 1922 |  | 
|---|
| 1923 | if (data.unique_name_in_owner) { | 
|---|
| 1924 | _acquire_unique_name_in_owner(); | 
|---|
| 1925 | } | 
|---|
| 1926 | } | 
|---|
| 1927 |  | 
|---|
| 1928 | Node *Node::get_owner() const { | 
|---|
| 1929 | return data.owner; | 
|---|
| 1930 | } | 
|---|
| 1931 |  | 
|---|
| 1932 | void Node::_clean_up_owner() { | 
|---|
| 1933 | ERR_FAIL_NULL(data.owner); // Sanity check. | 
|---|
| 1934 |  | 
|---|
| 1935 | if (data.unique_name_in_owner) { | 
|---|
| 1936 | _release_unique_name_in_owner(); | 
|---|
| 1937 | } | 
|---|
| 1938 | data.owner->data.owned.erase(data.OW); | 
|---|
| 1939 | data.owner = nullptr; | 
|---|
| 1940 | data.OW = nullptr; | 
|---|
| 1941 | } | 
|---|
| 1942 |  | 
|---|
| 1943 | Node *Node::find_common_parent_with(const Node *p_node) const { | 
|---|
| 1944 | if (this == p_node) { | 
|---|
| 1945 | return const_cast<Node *>(p_node); | 
|---|
| 1946 | } | 
|---|
| 1947 |  | 
|---|
| 1948 | HashSet<const Node *> visited; | 
|---|
| 1949 |  | 
|---|
| 1950 | const Node *n = this; | 
|---|
| 1951 |  | 
|---|
| 1952 | while (n) { | 
|---|
| 1953 | visited.insert(n); | 
|---|
| 1954 | n = n->data.parent; | 
|---|
| 1955 | } | 
|---|
| 1956 |  | 
|---|
| 1957 | const Node *common_parent = p_node; | 
|---|
| 1958 |  | 
|---|
| 1959 | while (common_parent) { | 
|---|
| 1960 | if (visited.has(common_parent)) { | 
|---|
| 1961 | break; | 
|---|
| 1962 | } | 
|---|
| 1963 | common_parent = common_parent->data.parent; | 
|---|
| 1964 | } | 
|---|
| 1965 |  | 
|---|
| 1966 | if (!common_parent) { | 
|---|
| 1967 | return nullptr; | 
|---|
| 1968 | } | 
|---|
| 1969 |  | 
|---|
| 1970 | return const_cast<Node *>(common_parent); | 
|---|
| 1971 | } | 
|---|
| 1972 |  | 
|---|
| 1973 | NodePath Node::get_path_to(const Node *p_node, bool p_use_unique_path) const { | 
|---|
| 1974 | ERR_FAIL_NULL_V(p_node, NodePath()); | 
|---|
| 1975 |  | 
|---|
| 1976 | if (this == p_node) { | 
|---|
| 1977 | return NodePath( "."); | 
|---|
| 1978 | } | 
|---|
| 1979 |  | 
|---|
| 1980 | HashSet<const Node *> visited; | 
|---|
| 1981 |  | 
|---|
| 1982 | const Node *n = this; | 
|---|
| 1983 |  | 
|---|
| 1984 | while (n) { | 
|---|
| 1985 | visited.insert(n); | 
|---|
| 1986 | n = n->data.parent; | 
|---|
| 1987 | } | 
|---|
| 1988 |  | 
|---|
| 1989 | const Node *common_parent = p_node; | 
|---|
| 1990 |  | 
|---|
| 1991 | while (common_parent) { | 
|---|
| 1992 | if (visited.has(common_parent)) { | 
|---|
| 1993 | break; | 
|---|
| 1994 | } | 
|---|
| 1995 | common_parent = common_parent->data.parent; | 
|---|
| 1996 | } | 
|---|
| 1997 |  | 
|---|
| 1998 | ERR_FAIL_NULL_V(common_parent, NodePath()); //nodes not in the same tree | 
|---|
| 1999 |  | 
|---|
| 2000 | visited.clear(); | 
|---|
| 2001 |  | 
|---|
| 2002 | Vector<StringName> path; | 
|---|
| 2003 | StringName up = String( ".."); | 
|---|
| 2004 |  | 
|---|
| 2005 | if (p_use_unique_path) { | 
|---|
| 2006 | n = p_node; | 
|---|
| 2007 |  | 
|---|
| 2008 | bool is_detected = false; | 
|---|
| 2009 | while (n != common_parent) { | 
|---|
| 2010 | if (n->is_unique_name_in_owner() && n->get_owner() == get_owner()) { | 
|---|
| 2011 | path.push_back(UNIQUE_NODE_PREFIX + String(n->get_name())); | 
|---|
| 2012 | is_detected = true; | 
|---|
| 2013 | break; | 
|---|
| 2014 | } | 
|---|
| 2015 | path.push_back(n->get_name()); | 
|---|
| 2016 | n = n->data.parent; | 
|---|
| 2017 | } | 
|---|
| 2018 |  | 
|---|
| 2019 | if (!is_detected) { | 
|---|
| 2020 | n = this; | 
|---|
| 2021 |  | 
|---|
| 2022 | String detected_name; | 
|---|
| 2023 | int up_count = 0; | 
|---|
| 2024 | while (n != common_parent) { | 
|---|
| 2025 | if (n->is_unique_name_in_owner() && n->get_owner() == get_owner()) { | 
|---|
| 2026 | detected_name = n->get_name(); | 
|---|
| 2027 | up_count = 0; | 
|---|
| 2028 | } | 
|---|
| 2029 | up_count++; | 
|---|
| 2030 | n = n->data.parent; | 
|---|
| 2031 | } | 
|---|
| 2032 |  | 
|---|
| 2033 | for (int i = 0; i < up_count; i++) { | 
|---|
| 2034 | path.push_back(up); | 
|---|
| 2035 | } | 
|---|
| 2036 |  | 
|---|
| 2037 | if (!detected_name.is_empty()) { | 
|---|
| 2038 | path.push_back(UNIQUE_NODE_PREFIX + detected_name); | 
|---|
| 2039 | } | 
|---|
| 2040 | } | 
|---|
| 2041 | } else { | 
|---|
| 2042 | n = p_node; | 
|---|
| 2043 |  | 
|---|
| 2044 | while (n != common_parent) { | 
|---|
| 2045 | path.push_back(n->get_name()); | 
|---|
| 2046 | n = n->data.parent; | 
|---|
| 2047 | } | 
|---|
| 2048 |  | 
|---|
| 2049 | n = this; | 
|---|
| 2050 |  | 
|---|
| 2051 | while (n != common_parent) { | 
|---|
| 2052 | path.push_back(up); | 
|---|
| 2053 | n = n->data.parent; | 
|---|
| 2054 | } | 
|---|
| 2055 | } | 
|---|
| 2056 |  | 
|---|
| 2057 | path.reverse(); | 
|---|
| 2058 |  | 
|---|
| 2059 | return NodePath(path, false); | 
|---|
| 2060 | } | 
|---|
| 2061 |  | 
|---|
| 2062 | NodePath Node::get_path() const { | 
|---|
| 2063 | ERR_FAIL_COND_V_MSG(!is_inside_tree(), NodePath(), "Cannot get path of node as it is not in a scene tree."); | 
|---|
| 2064 |  | 
|---|
| 2065 | if (data.path_cache) { | 
|---|
| 2066 | return *data.path_cache; | 
|---|
| 2067 | } | 
|---|
| 2068 |  | 
|---|
| 2069 | const Node *n = this; | 
|---|
| 2070 |  | 
|---|
| 2071 | Vector<StringName> path; | 
|---|
| 2072 |  | 
|---|
| 2073 | while (n) { | 
|---|
| 2074 | path.push_back(n->get_name()); | 
|---|
| 2075 | n = n->data.parent; | 
|---|
| 2076 | } | 
|---|
| 2077 |  | 
|---|
| 2078 | path.reverse(); | 
|---|
| 2079 |  | 
|---|
| 2080 | data.path_cache = memnew(NodePath(path, true)); | 
|---|
| 2081 |  | 
|---|
| 2082 | return *data.path_cache; | 
|---|
| 2083 | } | 
|---|
| 2084 |  | 
|---|
| 2085 | bool Node::is_in_group(const StringName &p_identifier) const { | 
|---|
| 2086 | ERR_THREAD_GUARD_V(false); | 
|---|
| 2087 | return data.grouped.has(p_identifier); | 
|---|
| 2088 | } | 
|---|
| 2089 |  | 
|---|
| 2090 | void Node::add_to_group(const StringName &p_identifier, bool p_persistent) { | 
|---|
| 2091 | ERR_THREAD_GUARD | 
|---|
| 2092 | ERR_FAIL_COND(!p_identifier.operator String().length()); | 
|---|
| 2093 |  | 
|---|
| 2094 | if (data.grouped.has(p_identifier)) { | 
|---|
| 2095 | return; | 
|---|
| 2096 | } | 
|---|
| 2097 |  | 
|---|
| 2098 | GroupData gd; | 
|---|
| 2099 |  | 
|---|
| 2100 | if (data.tree) { | 
|---|
| 2101 | gd.group = data.tree->add_to_group(p_identifier, this); | 
|---|
| 2102 | } else { | 
|---|
| 2103 | gd.group = nullptr; | 
|---|
| 2104 | } | 
|---|
| 2105 |  | 
|---|
| 2106 | gd.persistent = p_persistent; | 
|---|
| 2107 |  | 
|---|
| 2108 | data.grouped[p_identifier] = gd; | 
|---|
| 2109 | } | 
|---|
| 2110 |  | 
|---|
| 2111 | void Node::remove_from_group(const StringName &p_identifier) { | 
|---|
| 2112 | ERR_THREAD_GUARD | 
|---|
| 2113 | HashMap<StringName, GroupData>::Iterator E = data.grouped.find(p_identifier); | 
|---|
| 2114 |  | 
|---|
| 2115 | if (!E) { | 
|---|
| 2116 | return; | 
|---|
| 2117 | } | 
|---|
| 2118 |  | 
|---|
| 2119 | if (data.tree) { | 
|---|
| 2120 | data.tree->remove_from_group(E->key, this); | 
|---|
| 2121 | } | 
|---|
| 2122 |  | 
|---|
| 2123 | data.grouped.remove(E); | 
|---|
| 2124 | } | 
|---|
| 2125 |  | 
|---|
| 2126 | TypedArray<StringName> Node::_get_groups() const { | 
|---|
| 2127 | TypedArray<StringName> groups; | 
|---|
| 2128 | List<GroupInfo> gi; | 
|---|
| 2129 | get_groups(&gi); | 
|---|
| 2130 | for (const GroupInfo &E : gi) { | 
|---|
| 2131 | groups.push_back(E.name); | 
|---|
| 2132 | } | 
|---|
| 2133 |  | 
|---|
| 2134 | return groups; | 
|---|
| 2135 | } | 
|---|
| 2136 |  | 
|---|
| 2137 | void Node::get_groups(List<GroupInfo> *p_groups) const { | 
|---|
| 2138 | ERR_THREAD_GUARD | 
|---|
| 2139 | for (const KeyValue<StringName, GroupData> &E : data.grouped) { | 
|---|
| 2140 | GroupInfo gi; | 
|---|
| 2141 | gi.name = E.key; | 
|---|
| 2142 | gi.persistent = E.value.persistent; | 
|---|
| 2143 | p_groups->push_back(gi); | 
|---|
| 2144 | } | 
|---|
| 2145 | } | 
|---|
| 2146 |  | 
|---|
| 2147 | int Node::get_persistent_group_count() const { | 
|---|
| 2148 | ERR_THREAD_GUARD_V(0); | 
|---|
| 2149 | int count = 0; | 
|---|
| 2150 |  | 
|---|
| 2151 | for (const KeyValue<StringName, GroupData> &E : data.grouped) { | 
|---|
| 2152 | if (E.value.persistent) { | 
|---|
| 2153 | count += 1; | 
|---|
| 2154 | } | 
|---|
| 2155 | } | 
|---|
| 2156 |  | 
|---|
| 2157 | return count; | 
|---|
| 2158 | } | 
|---|
| 2159 |  | 
|---|
| 2160 | void Node::_print_tree_pretty(const String &prefix, const bool last) { | 
|---|
| 2161 | String new_prefix = last ? String::utf8( " â”–â•´") : String::utf8( " â” â•´"); | 
|---|
| 2162 | print_line(prefix + new_prefix + String(get_name())); | 
|---|
| 2163 | _update_children_cache(); | 
|---|
| 2164 | for (uint32_t i = 0; i < data.children_cache.size(); i++) { | 
|---|
| 2165 | new_prefix = last ? String::utf8( "   ") : String::utf8( " ┃ "); | 
|---|
| 2166 | data.children_cache[i]->_print_tree_pretty(prefix + new_prefix, i == data.children_cache.size() - 1); | 
|---|
| 2167 | } | 
|---|
| 2168 | } | 
|---|
| 2169 |  | 
|---|
| 2170 | void Node::print_tree_pretty() { | 
|---|
| 2171 | _print_tree_pretty( "", true); | 
|---|
| 2172 | } | 
|---|
| 2173 |  | 
|---|
| 2174 | void Node::print_tree() { | 
|---|
| 2175 | _print_tree(this); | 
|---|
| 2176 | } | 
|---|
| 2177 |  | 
|---|
| 2178 | void Node::_print_tree(const Node *p_node) { | 
|---|
| 2179 | print_line(String(p_node->get_path_to(this))); | 
|---|
| 2180 | _update_children_cache(); | 
|---|
| 2181 | for (uint32_t i = 0; i < data.children_cache.size(); i++) { | 
|---|
| 2182 | data.children_cache[i]->_print_tree(p_node); | 
|---|
| 2183 | } | 
|---|
| 2184 | } | 
|---|
| 2185 |  | 
|---|
| 2186 | void Node::_propagate_reverse_notification(int p_notification) { | 
|---|
| 2187 | data.blocked++; | 
|---|
| 2188 |  | 
|---|
| 2189 | for (HashMap<StringName, Node *>::Iterator I = data.children.last(); I; --I) { | 
|---|
| 2190 | I->value->_propagate_reverse_notification(p_notification); | 
|---|
| 2191 | } | 
|---|
| 2192 |  | 
|---|
| 2193 | notification(p_notification, true); | 
|---|
| 2194 | data.blocked--; | 
|---|
| 2195 | } | 
|---|
| 2196 |  | 
|---|
| 2197 | void Node::_propagate_deferred_notification(int p_notification, bool p_reverse) { | 
|---|
| 2198 | ERR_FAIL_COND(!is_inside_tree()); | 
|---|
| 2199 |  | 
|---|
| 2200 | data.blocked++; | 
|---|
| 2201 |  | 
|---|
| 2202 | if (!p_reverse) { | 
|---|
| 2203 | MessageQueue::get_singleton()->push_notification(this, p_notification); | 
|---|
| 2204 | } | 
|---|
| 2205 |  | 
|---|
| 2206 | for (KeyValue<StringName, Node *> &K : data.children) { | 
|---|
| 2207 | K.value->_propagate_deferred_notification(p_notification, p_reverse); | 
|---|
| 2208 | } | 
|---|
| 2209 |  | 
|---|
| 2210 | if (p_reverse) { | 
|---|
| 2211 | MessageQueue::get_singleton()->push_notification(this, p_notification); | 
|---|
| 2212 | } | 
|---|
| 2213 |  | 
|---|
| 2214 | data.blocked--; | 
|---|
| 2215 | } | 
|---|
| 2216 |  | 
|---|
| 2217 | void Node::propagate_notification(int p_notification) { | 
|---|
| 2218 | ERR_THREAD_GUARD | 
|---|
| 2219 | data.blocked++; | 
|---|
| 2220 | notification(p_notification); | 
|---|
| 2221 |  | 
|---|
| 2222 | for (KeyValue<StringName, Node *> &K : data.children) { | 
|---|
| 2223 | K.value->propagate_notification(p_notification); | 
|---|
| 2224 | } | 
|---|
| 2225 | data.blocked--; | 
|---|
| 2226 | } | 
|---|
| 2227 |  | 
|---|
| 2228 | void Node::propagate_call(const StringName &p_method, const Array &p_args, const bool p_parent_first) { | 
|---|
| 2229 | ERR_THREAD_GUARD | 
|---|
| 2230 | data.blocked++; | 
|---|
| 2231 |  | 
|---|
| 2232 | if (p_parent_first && has_method(p_method)) { | 
|---|
| 2233 | callv(p_method, p_args); | 
|---|
| 2234 | } | 
|---|
| 2235 |  | 
|---|
| 2236 | for (KeyValue<StringName, Node *> &K : data.children) { | 
|---|
| 2237 | K.value->propagate_call(p_method, p_args, p_parent_first); | 
|---|
| 2238 | } | 
|---|
| 2239 |  | 
|---|
| 2240 | if (!p_parent_first && has_method(p_method)) { | 
|---|
| 2241 | callv(p_method, p_args); | 
|---|
| 2242 | } | 
|---|
| 2243 |  | 
|---|
| 2244 | data.blocked--; | 
|---|
| 2245 | } | 
|---|
| 2246 |  | 
|---|
| 2247 | void Node::_propagate_replace_owner(Node *p_owner, Node *p_by_owner) { | 
|---|
| 2248 | if (get_owner() == p_owner) { | 
|---|
| 2249 | set_owner(p_by_owner); | 
|---|
| 2250 | } | 
|---|
| 2251 |  | 
|---|
| 2252 | data.blocked++; | 
|---|
| 2253 | for (KeyValue<StringName, Node *> &K : data.children) { | 
|---|
| 2254 | K.value->_propagate_replace_owner(p_owner, p_by_owner); | 
|---|
| 2255 | } | 
|---|
| 2256 | data.blocked--; | 
|---|
| 2257 | } | 
|---|
| 2258 |  | 
|---|
| 2259 | Ref<Tween> Node::create_tween() { | 
|---|
| 2260 | ERR_THREAD_GUARD_V(Ref<Tween>()); | 
|---|
| 2261 | ERR_FAIL_NULL_V_MSG(data.tree, nullptr, "Can't create Tween when not inside scene tree."); | 
|---|
| 2262 | Ref<Tween> tween = get_tree()->create_tween(); | 
|---|
| 2263 | tween->bind_node(this); | 
|---|
| 2264 | return tween; | 
|---|
| 2265 | } | 
|---|
| 2266 |  | 
|---|
| 2267 | void Node::set_scene_file_path(const String &p_scene_file_path) { | 
|---|
| 2268 | ERR_THREAD_GUARD | 
|---|
| 2269 | data.scene_file_path = p_scene_file_path; | 
|---|
| 2270 | } | 
|---|
| 2271 |  | 
|---|
| 2272 | String Node::get_scene_file_path() const { | 
|---|
| 2273 | return data.scene_file_path; | 
|---|
| 2274 | } | 
|---|
| 2275 |  | 
|---|
| 2276 | void Node::set_editor_description(const String &p_editor_description) { | 
|---|
| 2277 | ERR_THREAD_GUARD | 
|---|
| 2278 | if (data.editor_description == p_editor_description) { | 
|---|
| 2279 | return; | 
|---|
| 2280 | } | 
|---|
| 2281 |  | 
|---|
| 2282 | data.editor_description = p_editor_description; | 
|---|
| 2283 |  | 
|---|
| 2284 | if (Engine::get_singleton()->is_editor_hint() && is_inside_tree()) { | 
|---|
| 2285 | // Update tree so the tooltip in the Scene tree dock is also updated in the editor. | 
|---|
| 2286 | get_tree()->tree_changed(); | 
|---|
| 2287 | } | 
|---|
| 2288 | } | 
|---|
| 2289 |  | 
|---|
| 2290 | String Node::get_editor_description() const { | 
|---|
| 2291 | return data.editor_description; | 
|---|
| 2292 | } | 
|---|
| 2293 |  | 
|---|
| 2294 | void Node::set_editable_instance(Node *p_node, bool p_editable) { | 
|---|
| 2295 | ERR_THREAD_GUARD | 
|---|
| 2296 | ERR_FAIL_NULL(p_node); | 
|---|
| 2297 | ERR_FAIL_COND(!is_ancestor_of(p_node)); | 
|---|
| 2298 | if (!p_editable) { | 
|---|
| 2299 | p_node->data.editable_instance = false; | 
|---|
| 2300 | // Avoid this flag being needlessly saved; | 
|---|
| 2301 | // also give more visual feedback if editable children are re-enabled | 
|---|
| 2302 | set_display_folded(false); | 
|---|
| 2303 | } else { | 
|---|
| 2304 | p_node->data.editable_instance = true; | 
|---|
| 2305 | } | 
|---|
| 2306 | } | 
|---|
| 2307 |  | 
|---|
| 2308 | bool Node::is_editable_instance(const Node *p_node) const { | 
|---|
| 2309 | if (!p_node) { | 
|---|
| 2310 | return false; // Easier, null is never editable. :) | 
|---|
| 2311 | } | 
|---|
| 2312 | ERR_FAIL_COND_V(!is_ancestor_of(p_node), false); | 
|---|
| 2313 | return p_node->data.editable_instance; | 
|---|
| 2314 | } | 
|---|
| 2315 |  | 
|---|
| 2316 | Node *Node::get_deepest_editable_node(Node *p_start_node) const { | 
|---|
| 2317 | ERR_THREAD_GUARD_V(nullptr); | 
|---|
| 2318 | ERR_FAIL_NULL_V(p_start_node, nullptr); | 
|---|
| 2319 | ERR_FAIL_COND_V(!is_ancestor_of(p_start_node), p_start_node); | 
|---|
| 2320 |  | 
|---|
| 2321 | Node const *iterated_item = p_start_node; | 
|---|
| 2322 | Node *node = p_start_node; | 
|---|
| 2323 |  | 
|---|
| 2324 | while (iterated_item->get_owner() && iterated_item->get_owner() != this) { | 
|---|
| 2325 | if (!is_editable_instance(iterated_item->get_owner())) { | 
|---|
| 2326 | node = iterated_item->get_owner(); | 
|---|
| 2327 | } | 
|---|
| 2328 |  | 
|---|
| 2329 | iterated_item = iterated_item->get_owner(); | 
|---|
| 2330 | } | 
|---|
| 2331 |  | 
|---|
| 2332 | return node; | 
|---|
| 2333 | } | 
|---|
| 2334 |  | 
|---|
| 2335 | #ifdef TOOLS_ENABLED | 
|---|
| 2336 | void Node::set_property_pinned(const String &p_property, bool p_pinned) { | 
|---|
| 2337 | ERR_THREAD_GUARD | 
|---|
| 2338 | bool current_pinned = false; | 
|---|
| 2339 | Array pinned = get_meta( "_edit_pinned_properties_", Array()); | 
|---|
| 2340 | StringName psa = get_property_store_alias(p_property); | 
|---|
| 2341 | current_pinned = pinned.has(psa); | 
|---|
| 2342 |  | 
|---|
| 2343 | if (current_pinned != p_pinned) { | 
|---|
| 2344 | if (p_pinned) { | 
|---|
| 2345 | pinned.append(psa); | 
|---|
| 2346 | } else { | 
|---|
| 2347 | pinned.erase(psa); | 
|---|
| 2348 | } | 
|---|
| 2349 | } | 
|---|
| 2350 |  | 
|---|
| 2351 | if (pinned.is_empty()) { | 
|---|
| 2352 | remove_meta( "_edit_pinned_properties_"); | 
|---|
| 2353 | } else { | 
|---|
| 2354 | set_meta( "_edit_pinned_properties_", pinned); | 
|---|
| 2355 | } | 
|---|
| 2356 | } | 
|---|
| 2357 |  | 
|---|
| 2358 | bool Node::is_property_pinned(const StringName &p_property) const { | 
|---|
| 2359 | Array pinned = get_meta( "_edit_pinned_properties_", Array()); | 
|---|
| 2360 | StringName psa = get_property_store_alias(p_property); | 
|---|
| 2361 | return pinned.has(psa); | 
|---|
| 2362 | } | 
|---|
| 2363 |  | 
|---|
| 2364 | StringName Node::get_property_store_alias(const StringName &p_property) const { | 
|---|
| 2365 | return p_property; | 
|---|
| 2366 | } | 
|---|
| 2367 |  | 
|---|
| 2368 | bool Node::is_part_of_edited_scene() const { | 
|---|
| 2369 | return Engine::get_singleton()->is_editor_hint() && is_inside_tree() && get_tree()->get_edited_scene_root() && | 
|---|
| 2370 | (get_tree()->get_edited_scene_root() == this || get_tree()->get_edited_scene_root()->is_ancestor_of(this)); | 
|---|
| 2371 | } | 
|---|
| 2372 | #endif | 
|---|
| 2373 |  | 
|---|
| 2374 | void Node::get_storable_properties(HashSet<StringName> &r_storable_properties) const { | 
|---|
| 2375 | ERR_THREAD_GUARD | 
|---|
| 2376 | List<PropertyInfo> pi; | 
|---|
| 2377 | get_property_list(&pi); | 
|---|
| 2378 | for (List<PropertyInfo>::Element *E = pi.front(); E; E = E->next()) { | 
|---|
| 2379 | if ((E->get().usage & PROPERTY_USAGE_STORAGE)) { | 
|---|
| 2380 | r_storable_properties.insert(E->get().name); | 
|---|
| 2381 | } | 
|---|
| 2382 | } | 
|---|
| 2383 | } | 
|---|
| 2384 |  | 
|---|
| 2385 | String Node::to_string() { | 
|---|
| 2386 | ERR_THREAD_GUARD_V(String()); | 
|---|
| 2387 | if (get_script_instance()) { | 
|---|
| 2388 | bool valid; | 
|---|
| 2389 | String ret = get_script_instance()->to_string(&valid); | 
|---|
| 2390 | if (valid) { | 
|---|
| 2391 | return ret; | 
|---|
| 2392 | } | 
|---|
| 2393 | } | 
|---|
| 2394 |  | 
|---|
| 2395 | return (get_name() ? String(get_name()) + ":": "") + Object::to_string(); | 
|---|
| 2396 | } | 
|---|
| 2397 |  | 
|---|
| 2398 | void Node::set_scene_instance_state(const Ref<SceneState> &p_state) { | 
|---|
| 2399 | ERR_THREAD_GUARD | 
|---|
| 2400 | data.instance_state = p_state; | 
|---|
| 2401 | } | 
|---|
| 2402 |  | 
|---|
| 2403 | Ref<SceneState> Node::get_scene_instance_state() const { | 
|---|
| 2404 | return data.instance_state; | 
|---|
| 2405 | } | 
|---|
| 2406 |  | 
|---|
| 2407 | void Node::set_scene_inherited_state(const Ref<SceneState> &p_state) { | 
|---|
| 2408 | ERR_THREAD_GUARD | 
|---|
| 2409 | data.inherited_state = p_state; | 
|---|
| 2410 | } | 
|---|
| 2411 |  | 
|---|
| 2412 | Ref<SceneState> Node::get_scene_inherited_state() const { | 
|---|
| 2413 | return data.inherited_state; | 
|---|
| 2414 | } | 
|---|
| 2415 |  | 
|---|
| 2416 | void Node::set_scene_instance_load_placeholder(bool p_enable) { | 
|---|
| 2417 | data.use_placeholder = p_enable; | 
|---|
| 2418 | } | 
|---|
| 2419 |  | 
|---|
| 2420 | bool Node::get_scene_instance_load_placeholder() const { | 
|---|
| 2421 | return data.use_placeholder; | 
|---|
| 2422 | } | 
|---|
| 2423 |  | 
|---|
| 2424 | Node *Node::_duplicate(int p_flags, HashMap<const Node *, Node *> *r_duplimap) const { | 
|---|
| 2425 | ERR_THREAD_GUARD_V(nullptr); | 
|---|
| 2426 | Node *node = nullptr; | 
|---|
| 2427 |  | 
|---|
| 2428 | bool instantiated = false; | 
|---|
| 2429 |  | 
|---|
| 2430 | if (Object::cast_to<InstancePlaceholder>(this)) { | 
|---|
| 2431 | const InstancePlaceholder *ip = Object::cast_to<const InstancePlaceholder>(this); | 
|---|
| 2432 | InstancePlaceholder *nip = memnew(InstancePlaceholder); | 
|---|
| 2433 | nip->set_instance_path(ip->get_instance_path()); | 
|---|
| 2434 | node = nip; | 
|---|
| 2435 |  | 
|---|
| 2436 | } else if ((p_flags & DUPLICATE_USE_INSTANTIATION) && !get_scene_file_path().is_empty()) { | 
|---|
| 2437 | Ref<PackedScene> res = ResourceLoader::load(get_scene_file_path()); | 
|---|
| 2438 | ERR_FAIL_COND_V(res.is_null(), nullptr); | 
|---|
| 2439 | PackedScene::GenEditState edit_state = PackedScene::GEN_EDIT_STATE_DISABLED; | 
|---|
| 2440 | #ifdef TOOLS_ENABLED | 
|---|
| 2441 | if (p_flags & DUPLICATE_FROM_EDITOR) { | 
|---|
| 2442 | edit_state = PackedScene::GEN_EDIT_STATE_INSTANCE; | 
|---|
| 2443 | } | 
|---|
| 2444 | #endif | 
|---|
| 2445 | node = res->instantiate(edit_state); | 
|---|
| 2446 | ERR_FAIL_NULL_V(node, nullptr); | 
|---|
| 2447 | node->set_scene_instance_load_placeholder(get_scene_instance_load_placeholder()); | 
|---|
| 2448 |  | 
|---|
| 2449 | instantiated = true; | 
|---|
| 2450 |  | 
|---|
| 2451 | } else { | 
|---|
| 2452 | Object *obj = ClassDB::instantiate(get_class()); | 
|---|
| 2453 | ERR_FAIL_NULL_V(obj, nullptr); | 
|---|
| 2454 | node = Object::cast_to<Node>(obj); | 
|---|
| 2455 | if (!node) { | 
|---|
| 2456 | memdelete(obj); | 
|---|
| 2457 | } | 
|---|
| 2458 | ERR_FAIL_NULL_V(node, nullptr); | 
|---|
| 2459 | } | 
|---|
| 2460 |  | 
|---|
| 2461 | if (!get_scene_file_path().is_empty()) { //an instance | 
|---|
| 2462 | node->set_scene_file_path(get_scene_file_path()); | 
|---|
| 2463 | node->data.editable_instance = data.editable_instance; | 
|---|
| 2464 | } | 
|---|
| 2465 |  | 
|---|
| 2466 | StringName script_property_name = CoreStringNames::get_singleton()->_script; | 
|---|
| 2467 |  | 
|---|
| 2468 | List<const Node *> hidden_roots; | 
|---|
| 2469 | List<const Node *> node_tree; | 
|---|
| 2470 | node_tree.push_front(this); | 
|---|
| 2471 |  | 
|---|
| 2472 | if (instantiated) { | 
|---|
| 2473 | // Since nodes in the instantiated hierarchy won't be duplicated explicitly, we need to make an inventory | 
|---|
| 2474 | // of all the nodes in the tree of the instantiated scene in order to transfer the values of the properties | 
|---|
| 2475 |  | 
|---|
| 2476 | Vector<const Node *> instance_roots; | 
|---|
| 2477 | instance_roots.push_back(this); | 
|---|
| 2478 |  | 
|---|
| 2479 | for (List<const Node *>::Element *N = node_tree.front(); N; N = N->next()) { | 
|---|
| 2480 | for (int i = 0; i < N->get()->get_child_count(); ++i) { | 
|---|
| 2481 | Node *descendant = N->get()->get_child(i); | 
|---|
| 2482 | // Skip nodes not really belonging to the instantiated hierarchy; they'll be processed normally later | 
|---|
| 2483 | // but remember non-instantiated nodes that are hidden below instantiated ones | 
|---|
| 2484 | if (!instance_roots.has(descendant->get_owner())) { | 
|---|
| 2485 | if (descendant->get_parent() && descendant->get_parent() != this && descendant->data.owner != descendant->get_parent()) { | 
|---|
| 2486 | hidden_roots.push_back(descendant); | 
|---|
| 2487 | } | 
|---|
| 2488 | continue; | 
|---|
| 2489 | } | 
|---|
| 2490 |  | 
|---|
| 2491 | node_tree.push_back(descendant); | 
|---|
| 2492 |  | 
|---|
| 2493 | if (!descendant->get_scene_file_path().is_empty() && instance_roots.has(descendant->get_owner())) { | 
|---|
| 2494 | instance_roots.push_back(descendant); | 
|---|
| 2495 | } | 
|---|
| 2496 | } | 
|---|
| 2497 | } | 
|---|
| 2498 | } | 
|---|
| 2499 |  | 
|---|
| 2500 | for (List<const Node *>::Element *N = node_tree.front(); N; N = N->next()) { | 
|---|
| 2501 | Node *current_node = node->get_node(get_path_to(N->get())); | 
|---|
| 2502 | ERR_CONTINUE(!current_node); | 
|---|
| 2503 |  | 
|---|
| 2504 | if (p_flags & DUPLICATE_SCRIPTS) { | 
|---|
| 2505 | bool is_valid = false; | 
|---|
| 2506 | Variant scr = N->get()->get(script_property_name, &is_valid); | 
|---|
| 2507 | if (is_valid) { | 
|---|
| 2508 | current_node->set(script_property_name, scr); | 
|---|
| 2509 | } | 
|---|
| 2510 | } | 
|---|
| 2511 |  | 
|---|
| 2512 | List<PropertyInfo> plist; | 
|---|
| 2513 | N->get()->get_property_list(&plist); | 
|---|
| 2514 |  | 
|---|
| 2515 | for (const PropertyInfo &E : plist) { | 
|---|
| 2516 | if (!(E.usage & PROPERTY_USAGE_STORAGE)) { | 
|---|
| 2517 | continue; | 
|---|
| 2518 | } | 
|---|
| 2519 | String name = E.name; | 
|---|
| 2520 | if (name == script_property_name) { | 
|---|
| 2521 | continue; | 
|---|
| 2522 | } | 
|---|
| 2523 |  | 
|---|
| 2524 | Variant value = N->get()->get(name).duplicate(true); | 
|---|
| 2525 |  | 
|---|
| 2526 | if (E.usage & PROPERTY_USAGE_ALWAYS_DUPLICATE) { | 
|---|
| 2527 | Resource *res = Object::cast_to<Resource>(value); | 
|---|
| 2528 | if (res) { // Duplicate only if it's a resource | 
|---|
| 2529 | current_node->set(name, res->duplicate()); | 
|---|
| 2530 | } | 
|---|
| 2531 |  | 
|---|
| 2532 | } else { | 
|---|
| 2533 | current_node->set(name, value); | 
|---|
| 2534 | } | 
|---|
| 2535 | } | 
|---|
| 2536 | } | 
|---|
| 2537 |  | 
|---|
| 2538 | if (get_name() != String()) { | 
|---|
| 2539 | node->set_name(get_name()); | 
|---|
| 2540 | } | 
|---|
| 2541 |  | 
|---|
| 2542 | #ifdef TOOLS_ENABLED | 
|---|
| 2543 | if ((p_flags & DUPLICATE_FROM_EDITOR) && r_duplimap) { | 
|---|
| 2544 | r_duplimap->insert(this, node); | 
|---|
| 2545 | } | 
|---|
| 2546 | #endif | 
|---|
| 2547 |  | 
|---|
| 2548 | if (p_flags & DUPLICATE_GROUPS) { | 
|---|
| 2549 | List<GroupInfo> gi; | 
|---|
| 2550 | get_groups(&gi); | 
|---|
| 2551 | for (const GroupInfo &E : gi) { | 
|---|
| 2552 | #ifdef TOOLS_ENABLED | 
|---|
| 2553 | if ((p_flags & DUPLICATE_FROM_EDITOR) && !E.persistent) { | 
|---|
| 2554 | continue; | 
|---|
| 2555 | } | 
|---|
| 2556 | #endif | 
|---|
| 2557 |  | 
|---|
| 2558 | node->add_to_group(E.name, E.persistent); | 
|---|
| 2559 | } | 
|---|
| 2560 | } | 
|---|
| 2561 |  | 
|---|
| 2562 | for (int i = 0; i < get_child_count(); i++) { | 
|---|
| 2563 | if (get_child(i)->data.parent_owned) { | 
|---|
| 2564 | continue; | 
|---|
| 2565 | } | 
|---|
| 2566 | if (instantiated && get_child(i)->data.owner == this) { | 
|---|
| 2567 | continue; //part of instance | 
|---|
| 2568 | } | 
|---|
| 2569 |  | 
|---|
| 2570 | Node *dup = get_child(i)->_duplicate(p_flags, r_duplimap); | 
|---|
| 2571 | if (!dup) { | 
|---|
| 2572 | memdelete(node); | 
|---|
| 2573 | return nullptr; | 
|---|
| 2574 | } | 
|---|
| 2575 |  | 
|---|
| 2576 | node->add_child(dup); | 
|---|
| 2577 | if (i < node->get_child_count() - 1) { | 
|---|
| 2578 | node->move_child(dup, i); | 
|---|
| 2579 | } | 
|---|
| 2580 | } | 
|---|
| 2581 |  | 
|---|
| 2582 | for (const Node *&E : hidden_roots) { | 
|---|
| 2583 | Node *parent = node->get_node(get_path_to(E->data.parent)); | 
|---|
| 2584 | if (!parent) { | 
|---|
| 2585 | memdelete(node); | 
|---|
| 2586 | return nullptr; | 
|---|
| 2587 | } | 
|---|
| 2588 |  | 
|---|
| 2589 | Node *dup = E->_duplicate(p_flags, r_duplimap); | 
|---|
| 2590 | if (!dup) { | 
|---|
| 2591 | memdelete(node); | 
|---|
| 2592 | return nullptr; | 
|---|
| 2593 | } | 
|---|
| 2594 |  | 
|---|
| 2595 | parent->add_child(dup); | 
|---|
| 2596 | int pos = E->get_index(); | 
|---|
| 2597 |  | 
|---|
| 2598 | if (pos < parent->get_child_count() - 1) { | 
|---|
| 2599 | parent->move_child(dup, pos); | 
|---|
| 2600 | } | 
|---|
| 2601 | } | 
|---|
| 2602 |  | 
|---|
| 2603 | return node; | 
|---|
| 2604 | } | 
|---|
| 2605 |  | 
|---|
| 2606 | Node *Node::duplicate(int p_flags) const { | 
|---|
| 2607 | ERR_THREAD_GUARD_V(nullptr); | 
|---|
| 2608 | Node *dupe = _duplicate(p_flags); | 
|---|
| 2609 |  | 
|---|
| 2610 | if (dupe && (p_flags & DUPLICATE_SIGNALS)) { | 
|---|
| 2611 | _duplicate_signals(this, dupe); | 
|---|
| 2612 | } | 
|---|
| 2613 |  | 
|---|
| 2614 | return dupe; | 
|---|
| 2615 | } | 
|---|
| 2616 |  | 
|---|
| 2617 | #ifdef TOOLS_ENABLED | 
|---|
| 2618 | Node *Node::duplicate_from_editor(HashMap<const Node *, Node *> &r_duplimap) const { | 
|---|
| 2619 | return duplicate_from_editor(r_duplimap, HashMap<Ref<Resource>, Ref<Resource>>()); | 
|---|
| 2620 | } | 
|---|
| 2621 |  | 
|---|
| 2622 | Node *Node::duplicate_from_editor(HashMap<const Node *, Node *> &r_duplimap, const HashMap<Ref<Resource>, Ref<Resource>> &p_resource_remap) const { | 
|---|
| 2623 | Node *dupe = _duplicate(DUPLICATE_SIGNALS | DUPLICATE_GROUPS | DUPLICATE_SCRIPTS | DUPLICATE_USE_INSTANTIATION | DUPLICATE_FROM_EDITOR, &r_duplimap); | 
|---|
| 2624 |  | 
|---|
| 2625 | // This is used by SceneTreeDock's paste functionality. When pasting to foreign scene, resources are duplicated. | 
|---|
| 2626 | if (!p_resource_remap.is_empty()) { | 
|---|
| 2627 | remap_node_resources(dupe, p_resource_remap); | 
|---|
| 2628 | } | 
|---|
| 2629 |  | 
|---|
| 2630 | // Duplication of signals must happen after all the node descendants have been copied, | 
|---|
| 2631 | // because re-targeting of connections from some descendant to another is not possible | 
|---|
| 2632 | // if the emitter node comes later in tree order than the receiver | 
|---|
| 2633 | _duplicate_signals(this, dupe); | 
|---|
| 2634 |  | 
|---|
| 2635 | return dupe; | 
|---|
| 2636 | } | 
|---|
| 2637 |  | 
|---|
| 2638 | void Node::remap_node_resources(Node *p_node, const HashMap<Ref<Resource>, Ref<Resource>> &p_resource_remap) const { | 
|---|
| 2639 | List<PropertyInfo> props; | 
|---|
| 2640 | p_node->get_property_list(&props); | 
|---|
| 2641 |  | 
|---|
| 2642 | for (const PropertyInfo &E : props) { | 
|---|
| 2643 | if (!(E.usage & PROPERTY_USAGE_STORAGE)) { | 
|---|
| 2644 | continue; | 
|---|
| 2645 | } | 
|---|
| 2646 |  | 
|---|
| 2647 | Variant v = p_node->get(E.name); | 
|---|
| 2648 | if (v.is_ref_counted()) { | 
|---|
| 2649 | Ref<Resource> res = v; | 
|---|
| 2650 | if (res.is_valid()) { | 
|---|
| 2651 | if (p_resource_remap.has(res)) { | 
|---|
| 2652 | p_node->set(E.name, p_resource_remap[res]); | 
|---|
| 2653 | remap_nested_resources(res, p_resource_remap); | 
|---|
| 2654 | } | 
|---|
| 2655 | } | 
|---|
| 2656 | } | 
|---|
| 2657 | } | 
|---|
| 2658 |  | 
|---|
| 2659 | for (int i = 0; i < p_node->get_child_count(); i++) { | 
|---|
| 2660 | remap_node_resources(p_node->get_child(i), p_resource_remap); | 
|---|
| 2661 | } | 
|---|
| 2662 | } | 
|---|
| 2663 |  | 
|---|
| 2664 | void Node::remap_nested_resources(Ref<Resource> p_resource, const HashMap<Ref<Resource>, Ref<Resource>> &p_resource_remap) const { | 
|---|
| 2665 | List<PropertyInfo> props; | 
|---|
| 2666 | p_resource->get_property_list(&props); | 
|---|
| 2667 |  | 
|---|
| 2668 | for (const PropertyInfo &E : props) { | 
|---|
| 2669 | if (!(E.usage & PROPERTY_USAGE_STORAGE)) { | 
|---|
| 2670 | continue; | 
|---|
| 2671 | } | 
|---|
| 2672 |  | 
|---|
| 2673 | Variant v = p_resource->get(E.name); | 
|---|
| 2674 | if (v.is_ref_counted()) { | 
|---|
| 2675 | Ref<Resource> res = v; | 
|---|
| 2676 | if (res.is_valid()) { | 
|---|
| 2677 | if (p_resource_remap.has(res)) { | 
|---|
| 2678 | p_resource->set(E.name, p_resource_remap[res]); | 
|---|
| 2679 | remap_nested_resources(res, p_resource_remap); | 
|---|
| 2680 | } | 
|---|
| 2681 | } | 
|---|
| 2682 | } | 
|---|
| 2683 | } | 
|---|
| 2684 | } | 
|---|
| 2685 | #endif | 
|---|
| 2686 |  | 
|---|
| 2687 | // Duplication of signals must happen after all the node descendants have been copied, | 
|---|
| 2688 | // because re-targeting of connections from some descendant to another is not possible | 
|---|
| 2689 | // if the emitter node comes later in tree order than the receiver | 
|---|
| 2690 | void Node::_duplicate_signals(const Node *p_original, Node *p_copy) const { | 
|---|
| 2691 | if ((this != p_original) && !(p_original->is_ancestor_of(this))) { | 
|---|
| 2692 | return; | 
|---|
| 2693 | } | 
|---|
| 2694 |  | 
|---|
| 2695 | List<const Node *> process_list; | 
|---|
| 2696 | process_list.push_back(this); | 
|---|
| 2697 | while (!process_list.is_empty()) { | 
|---|
| 2698 | const Node *n = process_list.front()->get(); | 
|---|
| 2699 | process_list.pop_front(); | 
|---|
| 2700 |  | 
|---|
| 2701 | List<Connection> conns; | 
|---|
| 2702 | n->get_all_signal_connections(&conns); | 
|---|
| 2703 |  | 
|---|
| 2704 | for (const Connection &E : conns) { | 
|---|
| 2705 | if (E.flags & CONNECT_PERSIST) { | 
|---|
| 2706 | //user connected | 
|---|
| 2707 | NodePath p = p_original->get_path_to(n); | 
|---|
| 2708 | Node *copy = p_copy->get_node(p); | 
|---|
| 2709 |  | 
|---|
| 2710 | Node *target = Object::cast_to<Node>(E.callable.get_object()); | 
|---|
| 2711 | if (!target) { | 
|---|
| 2712 | continue; | 
|---|
| 2713 | } | 
|---|
| 2714 | NodePath ptarget = p_original->get_path_to(target); | 
|---|
| 2715 |  | 
|---|
| 2716 | Node *copytarget = target; | 
|---|
| 2717 |  | 
|---|
| 2718 | // Attempt to find a path to the duplicate target, if it seems it's not part | 
|---|
| 2719 | // of the duplicated and not yet parented hierarchy then at least try to connect | 
|---|
| 2720 | // to the same target as the original | 
|---|
| 2721 |  | 
|---|
| 2722 | if (p_copy->has_node(ptarget)) { | 
|---|
| 2723 | copytarget = p_copy->get_node(ptarget); | 
|---|
| 2724 | } | 
|---|
| 2725 |  | 
|---|
| 2726 | if (copy && copytarget && E.callable.get_method() != StringName()) { | 
|---|
| 2727 | Callable copy_callable = Callable(copytarget, E.callable.get_method()); | 
|---|
| 2728 | if (!copy->is_connected(E.signal.get_name(), copy_callable)) { | 
|---|
| 2729 | int arg_count = E.callable.get_bound_arguments_count(); | 
|---|
| 2730 | if (arg_count > 0) { | 
|---|
| 2731 | copy_callable = copy_callable.bindv(E.callable.get_bound_arguments()); | 
|---|
| 2732 | } else if (arg_count < 0) { | 
|---|
| 2733 | copy_callable = copy_callable.unbind(-arg_count); | 
|---|
| 2734 | } | 
|---|
| 2735 | copy->connect(E.signal.get_name(), copy_callable, E.flags); | 
|---|
| 2736 | } | 
|---|
| 2737 | } | 
|---|
| 2738 | } | 
|---|
| 2739 | } | 
|---|
| 2740 |  | 
|---|
| 2741 | for (int i = 0; i < n->get_child_count(); i++) { | 
|---|
| 2742 | process_list.push_back(n->get_child(i)); | 
|---|
| 2743 | } | 
|---|
| 2744 | } | 
|---|
| 2745 | } | 
|---|
| 2746 |  | 
|---|
| 2747 | static void find_owned_by(Node *p_by, Node *p_node, List<Node *> *p_owned) { | 
|---|
| 2748 | if (p_node->get_owner() == p_by) { | 
|---|
| 2749 | p_owned->push_back(p_node); | 
|---|
| 2750 | } | 
|---|
| 2751 |  | 
|---|
| 2752 | for (int i = 0; i < p_node->get_child_count(); i++) { | 
|---|
| 2753 | find_owned_by(p_by, p_node->get_child(i), p_owned); | 
|---|
| 2754 | } | 
|---|
| 2755 | } | 
|---|
| 2756 |  | 
|---|
| 2757 | void Node::replace_by(Node *p_node, bool p_keep_groups) { | 
|---|
| 2758 | ERR_THREAD_GUARD | 
|---|
| 2759 | ERR_FAIL_NULL(p_node); | 
|---|
| 2760 | ERR_FAIL_COND(p_node->data.parent); | 
|---|
| 2761 |  | 
|---|
| 2762 | List<Node *> owned = data.owned; | 
|---|
| 2763 | List<Node *> owned_by_owner; | 
|---|
| 2764 | Node *owner = (data.owner == this) ? p_node : data.owner; | 
|---|
| 2765 |  | 
|---|
| 2766 | if (p_keep_groups) { | 
|---|
| 2767 | List<GroupInfo> groups; | 
|---|
| 2768 | get_groups(&groups); | 
|---|
| 2769 |  | 
|---|
| 2770 | for (const GroupInfo &E : groups) { | 
|---|
| 2771 | p_node->add_to_group(E.name, E.persistent); | 
|---|
| 2772 | } | 
|---|
| 2773 | } | 
|---|
| 2774 |  | 
|---|
| 2775 | _replace_connections_target(p_node); | 
|---|
| 2776 |  | 
|---|
| 2777 | if (data.owner) { | 
|---|
| 2778 | for (int i = 0; i < get_child_count(); i++) { | 
|---|
| 2779 | find_owned_by(data.owner, get_child(i), &owned_by_owner); | 
|---|
| 2780 | } | 
|---|
| 2781 |  | 
|---|
| 2782 | _clean_up_owner(); | 
|---|
| 2783 | } | 
|---|
| 2784 |  | 
|---|
| 2785 | Node *parent = data.parent; | 
|---|
| 2786 | int index_in_parent = get_index(); | 
|---|
| 2787 |  | 
|---|
| 2788 | if (data.parent) { | 
|---|
| 2789 | parent->remove_child(this); | 
|---|
| 2790 | parent->add_child(p_node); | 
|---|
| 2791 | parent->move_child(p_node, index_in_parent); | 
|---|
| 2792 | } | 
|---|
| 2793 |  | 
|---|
| 2794 | emit_signal(SNAME( "replacing_by"), p_node); | 
|---|
| 2795 |  | 
|---|
| 2796 | while (get_child_count()) { | 
|---|
| 2797 | Node *child = get_child(0); | 
|---|
| 2798 | remove_child(child); | 
|---|
| 2799 | if (!child->is_owned_by_parent()) { | 
|---|
| 2800 | // add the custom children to the p_node | 
|---|
| 2801 | p_node->add_child(child); | 
|---|
| 2802 | } | 
|---|
| 2803 | } | 
|---|
| 2804 |  | 
|---|
| 2805 | p_node->set_owner(owner); | 
|---|
| 2806 | for (int i = 0; i < owned.size(); i++) { | 
|---|
| 2807 | owned[i]->set_owner(p_node); | 
|---|
| 2808 | } | 
|---|
| 2809 |  | 
|---|
| 2810 | for (int i = 0; i < owned_by_owner.size(); i++) { | 
|---|
| 2811 | owned_by_owner[i]->set_owner(owner); | 
|---|
| 2812 | } | 
|---|
| 2813 |  | 
|---|
| 2814 | p_node->set_scene_file_path(get_scene_file_path()); | 
|---|
| 2815 | } | 
|---|
| 2816 |  | 
|---|
| 2817 | void Node::_replace_connections_target(Node *p_new_target) { | 
|---|
| 2818 | List<Connection> cl; | 
|---|
| 2819 | get_signals_connected_to_this(&cl); | 
|---|
| 2820 |  | 
|---|
| 2821 | for (const Connection &c : cl) { | 
|---|
| 2822 | if (c.flags & CONNECT_PERSIST) { | 
|---|
| 2823 | c.signal.get_object()->disconnect(c.signal.get_name(), Callable(this, c.callable.get_method())); | 
|---|
| 2824 | bool valid = p_new_target->has_method(c.callable.get_method()) || Ref<Script>(p_new_target->get_script()).is_null() || Ref<Script>(p_new_target->get_script())->has_method(c.callable.get_method()); | 
|---|
| 2825 | ERR_CONTINUE_MSG(!valid, vformat( "Attempt to connect signal '%s.%s' to nonexistent method '%s.%s'.", c.signal.get_object()->get_class(), c.signal.get_name(), c.callable.get_object()->get_class(), c.callable.get_method())); | 
|---|
| 2826 | c.signal.get_object()->connect(c.signal.get_name(), Callable(p_new_target, c.callable.get_method()), c.flags); | 
|---|
| 2827 | } | 
|---|
| 2828 | } | 
|---|
| 2829 | } | 
|---|
| 2830 |  | 
|---|
| 2831 | bool Node::has_node_and_resource(const NodePath &p_path) const { | 
|---|
| 2832 | ERR_THREAD_GUARD_V(false); | 
|---|
| 2833 | if (!has_node(p_path)) { | 
|---|
| 2834 | return false; | 
|---|
| 2835 | } | 
|---|
| 2836 | Ref<Resource> res; | 
|---|
| 2837 | Vector<StringName> leftover_path; | 
|---|
| 2838 | Node *node = get_node_and_resource(p_path, res, leftover_path, false); | 
|---|
| 2839 |  | 
|---|
| 2840 | return node; | 
|---|
| 2841 | } | 
|---|
| 2842 |  | 
|---|
| 2843 | Array Node::_get_node_and_resource(const NodePath &p_path) { | 
|---|
| 2844 | Ref<Resource> res; | 
|---|
| 2845 | Vector<StringName> leftover_path; | 
|---|
| 2846 | Node *node = get_node_and_resource(p_path, res, leftover_path, false); | 
|---|
| 2847 | Array result; | 
|---|
| 2848 |  | 
|---|
| 2849 | if (node) { | 
|---|
| 2850 | result.push_back(node); | 
|---|
| 2851 | } else { | 
|---|
| 2852 | result.push_back(Variant()); | 
|---|
| 2853 | } | 
|---|
| 2854 |  | 
|---|
| 2855 | if (res.is_valid()) { | 
|---|
| 2856 | result.push_back(res); | 
|---|
| 2857 | } else { | 
|---|
| 2858 | result.push_back(Variant()); | 
|---|
| 2859 | } | 
|---|
| 2860 |  | 
|---|
| 2861 | result.push_back(NodePath(Vector<StringName>(), leftover_path, false)); | 
|---|
| 2862 |  | 
|---|
| 2863 | return result; | 
|---|
| 2864 | } | 
|---|
| 2865 |  | 
|---|
| 2866 | Node *Node::get_node_and_resource(const NodePath &p_path, Ref<Resource> &r_res, Vector<StringName> &r_leftover_subpath, bool p_last_is_property) const { | 
|---|
| 2867 | ERR_THREAD_GUARD_V(nullptr); | 
|---|
| 2868 | Node *node = get_node(p_path); | 
|---|
| 2869 | r_res = Ref<Resource>(); | 
|---|
| 2870 | r_leftover_subpath = Vector<StringName>(); | 
|---|
| 2871 | if (!node) { | 
|---|
| 2872 | return nullptr; | 
|---|
| 2873 | } | 
|---|
| 2874 |  | 
|---|
| 2875 | if (p_path.get_subname_count()) { | 
|---|
| 2876 | int j = 0; | 
|---|
| 2877 | // If not p_last_is_property, we shouldn't consider the last one as part of the resource | 
|---|
| 2878 | for (; j < p_path.get_subname_count() - (int)p_last_is_property; j++) { | 
|---|
| 2879 | bool is_valid = false; | 
|---|
| 2880 | Variant new_res_v = j == 0 ? node->get(p_path.get_subname(j), &is_valid) : r_res->get(p_path.get_subname(j), &is_valid); | 
|---|
| 2881 |  | 
|---|
| 2882 | if (!is_valid) { // Found nothing on that path | 
|---|
| 2883 | return nullptr; | 
|---|
| 2884 | } | 
|---|
| 2885 |  | 
|---|
| 2886 | Ref<Resource> new_res = new_res_v; | 
|---|
| 2887 |  | 
|---|
| 2888 | if (new_res.is_null()) { // No longer a resource, assume property | 
|---|
| 2889 | break; | 
|---|
| 2890 | } | 
|---|
| 2891 |  | 
|---|
| 2892 | r_res = new_res; | 
|---|
| 2893 | } | 
|---|
| 2894 | for (; j < p_path.get_subname_count(); j++) { | 
|---|
| 2895 | // Put the rest of the subpath in the leftover path | 
|---|
| 2896 | r_leftover_subpath.push_back(p_path.get_subname(j)); | 
|---|
| 2897 | } | 
|---|
| 2898 | } | 
|---|
| 2899 |  | 
|---|
| 2900 | return node; | 
|---|
| 2901 | } | 
|---|
| 2902 |  | 
|---|
| 2903 | void Node::_set_tree(SceneTree *p_tree) { | 
|---|
| 2904 | SceneTree *tree_changed_a = nullptr; | 
|---|
| 2905 | SceneTree *tree_changed_b = nullptr; | 
|---|
| 2906 |  | 
|---|
| 2907 | //ERR_FAIL_COND(p_scene && data.parent && !data.parent->data.scene); //nobug if both are null | 
|---|
| 2908 |  | 
|---|
| 2909 | if (data.tree) { | 
|---|
| 2910 | _propagate_exit_tree(); | 
|---|
| 2911 |  | 
|---|
| 2912 | tree_changed_a = data.tree; | 
|---|
| 2913 | } | 
|---|
| 2914 |  | 
|---|
| 2915 | data.tree = p_tree; | 
|---|
| 2916 |  | 
|---|
| 2917 | if (data.tree) { | 
|---|
| 2918 | _propagate_enter_tree(); | 
|---|
| 2919 | if (!data.parent || data.parent->data.ready_notified) { // No parent (root) or parent ready | 
|---|
| 2920 | _propagate_ready(); //reverse_notification(NOTIFICATION_READY); | 
|---|
| 2921 | } | 
|---|
| 2922 |  | 
|---|
| 2923 | tree_changed_b = data.tree; | 
|---|
| 2924 | } | 
|---|
| 2925 |  | 
|---|
| 2926 | if (tree_changed_a) { | 
|---|
| 2927 | tree_changed_a->tree_changed(); | 
|---|
| 2928 | } | 
|---|
| 2929 | if (tree_changed_b) { | 
|---|
| 2930 | tree_changed_b->tree_changed(); | 
|---|
| 2931 | } | 
|---|
| 2932 | } | 
|---|
| 2933 |  | 
|---|
| 2934 | #ifdef DEBUG_ENABLED | 
|---|
| 2935 | static HashMap<ObjectID, List<String>> _print_orphan_nodes_map; | 
|---|
| 2936 |  | 
|---|
| 2937 | static void _print_orphan_nodes_routine(Object *p_obj) { | 
|---|
| 2938 | Node *n = Object::cast_to<Node>(p_obj); | 
|---|
| 2939 | if (!n) { | 
|---|
| 2940 | return; | 
|---|
| 2941 | } | 
|---|
| 2942 |  | 
|---|
| 2943 | if (n->is_inside_tree()) { | 
|---|
| 2944 | return; | 
|---|
| 2945 | } | 
|---|
| 2946 |  | 
|---|
| 2947 | Node *p = n; | 
|---|
| 2948 | while (p->get_parent()) { | 
|---|
| 2949 | p = p->get_parent(); | 
|---|
| 2950 | } | 
|---|
| 2951 |  | 
|---|
| 2952 | String path; | 
|---|
| 2953 | if (p == n) { | 
|---|
| 2954 | path = n->get_name(); | 
|---|
| 2955 | } else { | 
|---|
| 2956 | path = String(p->get_name()) + "/"+ p->get_path_to(n); | 
|---|
| 2957 | } | 
|---|
| 2958 |  | 
|---|
| 2959 | List<String> info_strings; | 
|---|
| 2960 | info_strings.push_back(path); | 
|---|
| 2961 | info_strings.push_back(n->get_class()); | 
|---|
| 2962 |  | 
|---|
| 2963 | _print_orphan_nodes_map[p_obj->get_instance_id()] = info_strings; | 
|---|
| 2964 | } | 
|---|
| 2965 | #endif // DEBUG_ENABLED | 
|---|
| 2966 |  | 
|---|
| 2967 | void Node::print_orphan_nodes() { | 
|---|
| 2968 | #ifdef DEBUG_ENABLED | 
|---|
| 2969 | // Make sure it's empty. | 
|---|
| 2970 | _print_orphan_nodes_map.clear(); | 
|---|
| 2971 |  | 
|---|
| 2972 | // Collect and print information about orphan nodes. | 
|---|
| 2973 | ObjectDB::debug_objects(_print_orphan_nodes_routine); | 
|---|
| 2974 |  | 
|---|
| 2975 | for (const KeyValue<ObjectID, List<String>> &E : _print_orphan_nodes_map) { | 
|---|
| 2976 | print_line(itos(E.key) + " - Stray Node: "+ E.value[0] + " (Type: "+ E.value[1] + ")"); | 
|---|
| 2977 | } | 
|---|
| 2978 |  | 
|---|
| 2979 | // Flush it after use. | 
|---|
| 2980 | _print_orphan_nodes_map.clear(); | 
|---|
| 2981 | #endif | 
|---|
| 2982 | } | 
|---|
| 2983 |  | 
|---|
| 2984 | void Node::queue_free() { | 
|---|
| 2985 | // There are users which instantiate multiple scene trees for their games. | 
|---|
| 2986 | // Use the node's own tree to handle its deletion when relevant. | 
|---|
| 2987 | if (is_inside_tree()) { | 
|---|
| 2988 | get_tree()->queue_delete(this); | 
|---|
| 2989 | } else { | 
|---|
| 2990 | SceneTree *tree = SceneTree::get_singleton(); | 
|---|
| 2991 | ERR_FAIL_NULL_MSG(tree, "Can't queue free a node when no SceneTree is available."); | 
|---|
| 2992 | tree->queue_delete(this); | 
|---|
| 2993 | } | 
|---|
| 2994 | } | 
|---|
| 2995 |  | 
|---|
| 2996 | void Node::set_import_path(const NodePath &p_import_path) { | 
|---|
| 2997 | #ifdef TOOLS_ENABLED | 
|---|
| 2998 | data.import_path = p_import_path; | 
|---|
| 2999 | #endif | 
|---|
| 3000 | } | 
|---|
| 3001 |  | 
|---|
| 3002 | NodePath Node::get_import_path() const { | 
|---|
| 3003 | #ifdef TOOLS_ENABLED | 
|---|
| 3004 | return data.import_path; | 
|---|
| 3005 | #else | 
|---|
| 3006 | return NodePath(); | 
|---|
| 3007 | #endif | 
|---|
| 3008 | } | 
|---|
| 3009 |  | 
|---|
| 3010 | static void _add_nodes_to_options(const Node *p_base, const Node *p_node, List<String> *r_options) { | 
|---|
| 3011 | if (p_node != p_base && !p_node->get_owner()) { | 
|---|
| 3012 | return; | 
|---|
| 3013 | } | 
|---|
| 3014 | String n = p_base->get_path_to(p_node); | 
|---|
| 3015 | r_options->push_back(n.quote()); | 
|---|
| 3016 | for (int i = 0; i < p_node->get_child_count(); i++) { | 
|---|
| 3017 | _add_nodes_to_options(p_base, p_node->get_child(i), r_options); | 
|---|
| 3018 | } | 
|---|
| 3019 | } | 
|---|
| 3020 |  | 
|---|
| 3021 | void Node::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const { | 
|---|
| 3022 | String pf = p_function; | 
|---|
| 3023 | if ((pf == "has_node"|| pf == "get_node") && p_idx == 0) { | 
|---|
| 3024 | _add_nodes_to_options(this, this, r_options); | 
|---|
| 3025 | } | 
|---|
| 3026 | Object::get_argument_options(p_function, p_idx, r_options); | 
|---|
| 3027 | } | 
|---|
| 3028 |  | 
|---|
| 3029 | void Node::clear_internal_tree_resource_paths() { | 
|---|
| 3030 | clear_internal_resource_paths(); | 
|---|
| 3031 | for (KeyValue<StringName, Node *> &K : data.children) { | 
|---|
| 3032 | K.value->clear_internal_tree_resource_paths(); | 
|---|
| 3033 | } | 
|---|
| 3034 | } | 
|---|
| 3035 |  | 
|---|
| 3036 | PackedStringArray Node::get_configuration_warnings() const { | 
|---|
| 3037 | ERR_THREAD_GUARD_V(PackedStringArray()); | 
|---|
| 3038 | PackedStringArray ret; | 
|---|
| 3039 |  | 
|---|
| 3040 | Vector<String> warnings; | 
|---|
| 3041 | if (GDVIRTUAL_CALL(_get_configuration_warnings, warnings)) { | 
|---|
| 3042 | ret.append_array(warnings); | 
|---|
| 3043 | } | 
|---|
| 3044 |  | 
|---|
| 3045 | return ret; | 
|---|
| 3046 | } | 
|---|
| 3047 |  | 
|---|
| 3048 | String Node::get_configuration_warnings_as_string() const { | 
|---|
| 3049 | PackedStringArray warnings = get_configuration_warnings(); | 
|---|
| 3050 | String all_warnings; | 
|---|
| 3051 | for (int i = 0; i < warnings.size(); i++) { | 
|---|
| 3052 | if (i > 0) { | 
|---|
| 3053 | all_warnings += "\n\n"; | 
|---|
| 3054 | } | 
|---|
| 3055 | // Format as a bullet point list to make multiple warnings easier to distinguish | 
|---|
| 3056 | // from each other. | 
|---|
| 3057 | all_warnings += String::utf8( "•  ") + warnings[i]; | 
|---|
| 3058 | } | 
|---|
| 3059 | return all_warnings; | 
|---|
| 3060 | } | 
|---|
| 3061 |  | 
|---|
| 3062 | void Node::update_configuration_warnings() { | 
|---|
| 3063 | ERR_THREAD_GUARD | 
|---|
| 3064 | #ifdef TOOLS_ENABLED | 
|---|
| 3065 | if (!is_inside_tree()) { | 
|---|
| 3066 | return; | 
|---|
| 3067 | } | 
|---|
| 3068 | if (get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root() == this || get_tree()->get_edited_scene_root()->is_ancestor_of(this))) { | 
|---|
| 3069 | get_tree()->emit_signal(SceneStringNames::get_singleton()->node_configuration_warning_changed, this); | 
|---|
| 3070 | } | 
|---|
| 3071 | #endif | 
|---|
| 3072 | } | 
|---|
| 3073 |  | 
|---|
| 3074 | bool Node::is_owned_by_parent() const { | 
|---|
| 3075 | return data.parent_owned; | 
|---|
| 3076 | } | 
|---|
| 3077 |  | 
|---|
| 3078 | void Node::set_display_folded(bool p_folded) { | 
|---|
| 3079 | ERR_THREAD_GUARD | 
|---|
| 3080 | data.display_folded = p_folded; | 
|---|
| 3081 | } | 
|---|
| 3082 |  | 
|---|
| 3083 | bool Node::is_displayed_folded() const { | 
|---|
| 3084 | return data.display_folded; | 
|---|
| 3085 | } | 
|---|
| 3086 |  | 
|---|
| 3087 | bool Node::is_ready() const { | 
|---|
| 3088 | return !data.ready_first; | 
|---|
| 3089 | } | 
|---|
| 3090 |  | 
|---|
| 3091 | void Node::request_ready() { | 
|---|
| 3092 | ERR_THREAD_GUARD | 
|---|
| 3093 | data.ready_first = true; | 
|---|
| 3094 | } | 
|---|
| 3095 |  | 
|---|
| 3096 | void Node::_call_input(const Ref<InputEvent> &p_event) { | 
|---|
| 3097 | if (p_event->get_device() != InputEvent::DEVICE_ID_INTERNAL) { | 
|---|
| 3098 | GDVIRTUAL_CALL(_input, p_event); | 
|---|
| 3099 | } | 
|---|
| 3100 | if (!is_inside_tree() || !get_viewport() || get_viewport()->is_input_handled()) { | 
|---|
| 3101 | return; | 
|---|
| 3102 | } | 
|---|
| 3103 | input(p_event); | 
|---|
| 3104 | } | 
|---|
| 3105 |  | 
|---|
| 3106 | void Node::_call_shortcut_input(const Ref<InputEvent> &p_event) { | 
|---|
| 3107 | if (p_event->get_device() != InputEvent::DEVICE_ID_INTERNAL) { | 
|---|
| 3108 | GDVIRTUAL_CALL(_shortcut_input, p_event); | 
|---|
| 3109 | } | 
|---|
| 3110 | if (!is_inside_tree() || !get_viewport() || get_viewport()->is_input_handled()) { | 
|---|
| 3111 | return; | 
|---|
| 3112 | } | 
|---|
| 3113 | shortcut_input(p_event); | 
|---|
| 3114 | } | 
|---|
| 3115 |  | 
|---|
| 3116 | void Node::_call_unhandled_input(const Ref<InputEvent> &p_event) { | 
|---|
| 3117 | if (p_event->get_device() != InputEvent::DEVICE_ID_INTERNAL) { | 
|---|
| 3118 | GDVIRTUAL_CALL(_unhandled_input, p_event); | 
|---|
| 3119 | } | 
|---|
| 3120 | if (!is_inside_tree() || !get_viewport() || get_viewport()->is_input_handled()) { | 
|---|
| 3121 | return; | 
|---|
| 3122 | } | 
|---|
| 3123 | unhandled_input(p_event); | 
|---|
| 3124 | } | 
|---|
| 3125 |  | 
|---|
| 3126 | void Node::_call_unhandled_key_input(const Ref<InputEvent> &p_event) { | 
|---|
| 3127 | if (p_event->get_device() != InputEvent::DEVICE_ID_INTERNAL) { | 
|---|
| 3128 | GDVIRTUAL_CALL(_unhandled_key_input, p_event); | 
|---|
| 3129 | } | 
|---|
| 3130 | if (!is_inside_tree() || !get_viewport() || get_viewport()->is_input_handled()) { | 
|---|
| 3131 | return; | 
|---|
| 3132 | } | 
|---|
| 3133 | unhandled_key_input(p_event); | 
|---|
| 3134 | } | 
|---|
| 3135 |  | 
|---|
| 3136 | void Node::_validate_property(PropertyInfo &p_property) const { | 
|---|
| 3137 | if ((p_property.name == "process_thread_group_order"|| p_property.name == "process_thread_messages") && data.process_thread_group == PROCESS_THREAD_GROUP_INHERIT) { | 
|---|
| 3138 | p_property.usage = 0; | 
|---|
| 3139 | } | 
|---|
| 3140 | } | 
|---|
| 3141 |  | 
|---|
| 3142 | void Node::input(const Ref<InputEvent> &p_event) { | 
|---|
| 3143 | } | 
|---|
| 3144 |  | 
|---|
| 3145 | void Node::shortcut_input(const Ref<InputEvent> &p_key_event) { | 
|---|
| 3146 | } | 
|---|
| 3147 |  | 
|---|
| 3148 | void Node::unhandled_input(const Ref<InputEvent> &p_event) { | 
|---|
| 3149 | } | 
|---|
| 3150 |  | 
|---|
| 3151 | void Node::unhandled_key_input(const Ref<InputEvent> &p_key_event) { | 
|---|
| 3152 | } | 
|---|
| 3153 |  | 
|---|
| 3154 | Variant Node::_call_deferred_thread_group_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { | 
|---|
| 3155 | if (p_argcount < 1) { | 
|---|
| 3156 | r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; | 
|---|
| 3157 | r_error.argument = 0; | 
|---|
| 3158 | return Variant(); | 
|---|
| 3159 | } | 
|---|
| 3160 |  | 
|---|
| 3161 | if (p_args[0]->get_type() != Variant::STRING_NAME && p_args[0]->get_type() != Variant::STRING) { | 
|---|
| 3162 | r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; | 
|---|
| 3163 | r_error.argument = 0; | 
|---|
| 3164 | r_error.expected = Variant::STRING_NAME; | 
|---|
| 3165 | return Variant(); | 
|---|
| 3166 | } | 
|---|
| 3167 |  | 
|---|
| 3168 | r_error.error = Callable::CallError::CALL_OK; | 
|---|
| 3169 |  | 
|---|
| 3170 | StringName method = *p_args[0]; | 
|---|
| 3171 |  | 
|---|
| 3172 | call_deferred_thread_groupp(method, &p_args[1], p_argcount - 1, true); | 
|---|
| 3173 |  | 
|---|
| 3174 | return Variant(); | 
|---|
| 3175 | } | 
|---|
| 3176 |  | 
|---|
| 3177 | Variant Node::_call_thread_safe_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { | 
|---|
| 3178 | if (p_argcount < 1) { | 
|---|
| 3179 | r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; | 
|---|
| 3180 | r_error.argument = 0; | 
|---|
| 3181 | return Variant(); | 
|---|
| 3182 | } | 
|---|
| 3183 |  | 
|---|
| 3184 | if (p_args[0]->get_type() != Variant::STRING_NAME && p_args[0]->get_type() != Variant::STRING) { | 
|---|
| 3185 | r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; | 
|---|
| 3186 | r_error.argument = 0; | 
|---|
| 3187 | r_error.expected = Variant::STRING_NAME; | 
|---|
| 3188 | return Variant(); | 
|---|
| 3189 | } | 
|---|
| 3190 |  | 
|---|
| 3191 | r_error.error = Callable::CallError::CALL_OK; | 
|---|
| 3192 |  | 
|---|
| 3193 | StringName method = *p_args[0]; | 
|---|
| 3194 |  | 
|---|
| 3195 | call_thread_safep(method, &p_args[1], p_argcount - 1, true); | 
|---|
| 3196 |  | 
|---|
| 3197 | return Variant(); | 
|---|
| 3198 | } | 
|---|
| 3199 |  | 
|---|
| 3200 | void Node::call_deferred_thread_groupp(const StringName &p_method, const Variant **p_args, int p_argcount, bool p_show_error) { | 
|---|
| 3201 | ERR_FAIL_COND(!is_inside_tree()); | 
|---|
| 3202 | SceneTree::ProcessGroup *pg = (SceneTree::ProcessGroup *)data.process_group; | 
|---|
| 3203 | pg->call_queue.push_callp(this, p_method, p_args, p_argcount, p_show_error); | 
|---|
| 3204 | } | 
|---|
| 3205 | void Node::set_deferred_thread_group(const StringName &p_property, const Variant &p_value) { | 
|---|
| 3206 | ERR_FAIL_COND(!is_inside_tree()); | 
|---|
| 3207 | SceneTree::ProcessGroup *pg = (SceneTree::ProcessGroup *)data.process_group; | 
|---|
| 3208 | pg->call_queue.push_set(this, p_property, p_value); | 
|---|
| 3209 | } | 
|---|
| 3210 | void Node::notify_deferred_thread_group(int p_notification) { | 
|---|
| 3211 | ERR_FAIL_COND(!is_inside_tree()); | 
|---|
| 3212 | SceneTree::ProcessGroup *pg = (SceneTree::ProcessGroup *)data.process_group; | 
|---|
| 3213 | pg->call_queue.push_notification(this, p_notification); | 
|---|
| 3214 | } | 
|---|
| 3215 |  | 
|---|
| 3216 | void Node::call_thread_safep(const StringName &p_method, const Variant **p_args, int p_argcount, bool p_show_error) { | 
|---|
| 3217 | if (is_accessible_from_caller_thread()) { | 
|---|
| 3218 | Callable::CallError ce; | 
|---|
| 3219 | callp(p_method, p_args, p_argcount, ce); | 
|---|
| 3220 | if (p_show_error && ce.error != Callable::CallError::CALL_OK) { | 
|---|
| 3221 | ERR_FAIL_MSG( "Error calling method from 'call_threadp': "+ Variant::get_call_error_text(this, p_method, p_args, p_argcount, ce) + "."); | 
|---|
| 3222 | } | 
|---|
| 3223 | } else { | 
|---|
| 3224 | call_deferred_thread_groupp(p_method, p_args, p_argcount, p_show_error); | 
|---|
| 3225 | } | 
|---|
| 3226 | } | 
|---|
| 3227 | void Node::set_thread_safe(const StringName &p_property, const Variant &p_value) { | 
|---|
| 3228 | if (is_accessible_from_caller_thread()) { | 
|---|
| 3229 | set(p_property, p_value); | 
|---|
| 3230 | } else { | 
|---|
| 3231 | set_deferred_thread_group(p_property, p_value); | 
|---|
| 3232 | } | 
|---|
| 3233 | } | 
|---|
| 3234 | void Node::notify_thread_safe(int p_notification) { | 
|---|
| 3235 | if (is_accessible_from_caller_thread()) { | 
|---|
| 3236 | notification(p_notification); | 
|---|
| 3237 | } else { | 
|---|
| 3238 | notify_deferred_thread_group(p_notification); | 
|---|
| 3239 | } | 
|---|
| 3240 | } | 
|---|
| 3241 |  | 
|---|
| 3242 | void Node::_bind_methods() { | 
|---|
| 3243 | GLOBAL_DEF(PropertyInfo(Variant::INT, "editor/naming/node_name_num_separator", PROPERTY_HINT_ENUM, "None,Space,Underscore,Dash"), 0); | 
|---|
| 3244 | GLOBAL_DEF(PropertyInfo(Variant::INT, "editor/naming/node_name_casing", PROPERTY_HINT_ENUM, "PascalCase,camelCase,snake_case"), NAME_CASING_PASCAL_CASE); | 
|---|
| 3245 |  | 
|---|
| 3246 | ClassDB::bind_static_method( "Node", D_METHOD( "print_orphan_nodes"), &Node::print_orphan_nodes); | 
|---|
| 3247 | ClassDB::bind_method(D_METHOD( "add_sibling", "sibling", "force_readable_name"), &Node::add_sibling, DEFVAL(false)); | 
|---|
| 3248 |  | 
|---|
| 3249 | ClassDB::bind_method(D_METHOD( "set_name", "name"), &Node::set_name); | 
|---|
| 3250 | ClassDB::bind_method(D_METHOD( "get_name"), &Node::get_name); | 
|---|
| 3251 | ClassDB::bind_method(D_METHOD( "add_child", "node", "force_readable_name", "internal"), &Node::add_child, DEFVAL(false), DEFVAL(0)); | 
|---|
| 3252 | ClassDB::bind_method(D_METHOD( "remove_child", "node"), &Node::remove_child); | 
|---|
| 3253 | ClassDB::bind_method(D_METHOD( "reparent", "new_parent", "keep_global_transform"), &Node::reparent, DEFVAL(true)); | 
|---|
| 3254 | ClassDB::bind_method(D_METHOD( "get_child_count", "include_internal"), &Node::get_child_count, DEFVAL(false)); // Note that the default value bound for include_internal is false, while the method is declared with true. This is because internal nodes are irrelevant for GDSCript. | 
|---|
| 3255 | ClassDB::bind_method(D_METHOD( "get_children", "include_internal"), &Node::get_children, DEFVAL(false)); | 
|---|
| 3256 | ClassDB::bind_method(D_METHOD( "get_child", "idx", "include_internal"), &Node::get_child, DEFVAL(false)); | 
|---|
| 3257 | ClassDB::bind_method(D_METHOD( "has_node", "path"), &Node::has_node); | 
|---|
| 3258 | ClassDB::bind_method(D_METHOD( "get_node", "path"), &Node::get_node); | 
|---|
| 3259 | ClassDB::bind_method(D_METHOD( "get_node_or_null", "path"), &Node::get_node_or_null); | 
|---|
| 3260 | ClassDB::bind_method(D_METHOD( "get_parent"), &Node::get_parent); | 
|---|
| 3261 | ClassDB::bind_method(D_METHOD( "find_child", "pattern", "recursive", "owned"), &Node::find_child, DEFVAL(true), DEFVAL(true)); | 
|---|
| 3262 | ClassDB::bind_method(D_METHOD( "find_children", "pattern", "type", "recursive", "owned"), &Node::find_children, DEFVAL( ""), DEFVAL(true), DEFVAL(true)); | 
|---|
| 3263 | ClassDB::bind_method(D_METHOD( "find_parent", "pattern"), &Node::find_parent); | 
|---|
| 3264 | ClassDB::bind_method(D_METHOD( "has_node_and_resource", "path"), &Node::has_node_and_resource); | 
|---|
| 3265 | ClassDB::bind_method(D_METHOD( "get_node_and_resource", "path"), &Node::_get_node_and_resource); | 
|---|
| 3266 |  | 
|---|
| 3267 | ClassDB::bind_method(D_METHOD( "is_inside_tree"), &Node::is_inside_tree); | 
|---|
| 3268 | ClassDB::bind_method(D_METHOD( "is_ancestor_of", "node"), &Node::is_ancestor_of); | 
|---|
| 3269 | ClassDB::bind_method(D_METHOD( "is_greater_than", "node"), &Node::is_greater_than); | 
|---|
| 3270 | ClassDB::bind_method(D_METHOD( "get_path"), &Node::get_path); | 
|---|
| 3271 | ClassDB::bind_method(D_METHOD( "get_path_to", "node", "use_unique_path"), &Node::get_path_to, DEFVAL(false)); | 
|---|
| 3272 | ClassDB::bind_method(D_METHOD( "add_to_group", "group", "persistent"), &Node::add_to_group, DEFVAL(false)); | 
|---|
| 3273 | ClassDB::bind_method(D_METHOD( "remove_from_group", "group"), &Node::remove_from_group); | 
|---|
| 3274 | ClassDB::bind_method(D_METHOD( "is_in_group", "group"), &Node::is_in_group); | 
|---|
| 3275 | ClassDB::bind_method(D_METHOD( "move_child", "child_node", "to_index"), &Node::move_child); | 
|---|
| 3276 | ClassDB::bind_method(D_METHOD( "get_groups"), &Node::_get_groups); | 
|---|
| 3277 | ClassDB::bind_method(D_METHOD( "set_owner", "owner"), &Node::set_owner); | 
|---|
| 3278 | ClassDB::bind_method(D_METHOD( "get_owner"), &Node::get_owner); | 
|---|
| 3279 | ClassDB::bind_method(D_METHOD( "get_index", "include_internal"), &Node::get_index, DEFVAL(false)); | 
|---|
| 3280 | ClassDB::bind_method(D_METHOD( "print_tree"), &Node::print_tree); | 
|---|
| 3281 | ClassDB::bind_method(D_METHOD( "print_tree_pretty"), &Node::print_tree_pretty); | 
|---|
| 3282 | ClassDB::bind_method(D_METHOD( "set_scene_file_path", "scene_file_path"), &Node::set_scene_file_path); | 
|---|
| 3283 | ClassDB::bind_method(D_METHOD( "get_scene_file_path"), &Node::get_scene_file_path); | 
|---|
| 3284 | ClassDB::bind_method(D_METHOD( "propagate_notification", "what"), &Node::propagate_notification); | 
|---|
| 3285 | ClassDB::bind_method(D_METHOD( "propagate_call", "method", "args", "parent_first"), &Node::propagate_call, DEFVAL(Array()), DEFVAL(false)); | 
|---|
| 3286 | ClassDB::bind_method(D_METHOD( "set_physics_process", "enable"), &Node::set_physics_process); | 
|---|
| 3287 | ClassDB::bind_method(D_METHOD( "get_physics_process_delta_time"), &Node::get_physics_process_delta_time); | 
|---|
| 3288 | ClassDB::bind_method(D_METHOD( "is_physics_processing"), &Node::is_physics_processing); | 
|---|
| 3289 | ClassDB::bind_method(D_METHOD( "get_process_delta_time"), &Node::get_process_delta_time); | 
|---|
| 3290 | ClassDB::bind_method(D_METHOD( "set_process", "enable"), &Node::set_process); | 
|---|
| 3291 | ClassDB::bind_method(D_METHOD( "set_process_priority", "priority"), &Node::set_process_priority); | 
|---|
| 3292 | ClassDB::bind_method(D_METHOD( "get_process_priority"), &Node::get_process_priority); | 
|---|
| 3293 | ClassDB::bind_method(D_METHOD( "set_physics_process_priority", "priority"), &Node::set_physics_process_priority); | 
|---|
| 3294 | ClassDB::bind_method(D_METHOD( "get_physics_process_priority"), &Node::get_physics_process_priority); | 
|---|
| 3295 | ClassDB::bind_method(D_METHOD( "is_processing"), &Node::is_processing); | 
|---|
| 3296 | ClassDB::bind_method(D_METHOD( "set_process_input", "enable"), &Node::set_process_input); | 
|---|
| 3297 | ClassDB::bind_method(D_METHOD( "is_processing_input"), &Node::is_processing_input); | 
|---|
| 3298 | ClassDB::bind_method(D_METHOD( "set_process_shortcut_input", "enable"), &Node::set_process_shortcut_input); | 
|---|
| 3299 | ClassDB::bind_method(D_METHOD( "is_processing_shortcut_input"), &Node::is_processing_shortcut_input); | 
|---|
| 3300 | ClassDB::bind_method(D_METHOD( "set_process_unhandled_input", "enable"), &Node::set_process_unhandled_input); | 
|---|
| 3301 | ClassDB::bind_method(D_METHOD( "is_processing_unhandled_input"), &Node::is_processing_unhandled_input); | 
|---|
| 3302 | ClassDB::bind_method(D_METHOD( "set_process_unhandled_key_input", "enable"), &Node::set_process_unhandled_key_input); | 
|---|
| 3303 | ClassDB::bind_method(D_METHOD( "is_processing_unhandled_key_input"), &Node::is_processing_unhandled_key_input); | 
|---|
| 3304 | ClassDB::bind_method(D_METHOD( "set_process_mode", "mode"), &Node::set_process_mode); | 
|---|
| 3305 | ClassDB::bind_method(D_METHOD( "get_process_mode"), &Node::get_process_mode); | 
|---|
| 3306 | ClassDB::bind_method(D_METHOD( "can_process"), &Node::can_process); | 
|---|
| 3307 |  | 
|---|
| 3308 | ClassDB::bind_method(D_METHOD( "set_process_thread_group", "mode"), &Node::set_process_thread_group); | 
|---|
| 3309 | ClassDB::bind_method(D_METHOD( "get_process_thread_group"), &Node::get_process_thread_group); | 
|---|
| 3310 |  | 
|---|
| 3311 | ClassDB::bind_method(D_METHOD( "set_process_thread_messages", "flags"), &Node::set_process_thread_messages); | 
|---|
| 3312 | ClassDB::bind_method(D_METHOD( "get_process_thread_messages"), &Node::get_process_thread_messages); | 
|---|
| 3313 |  | 
|---|
| 3314 | ClassDB::bind_method(D_METHOD( "set_process_thread_group_order", "order"), &Node::set_process_thread_group_order); | 
|---|
| 3315 | ClassDB::bind_method(D_METHOD( "get_process_thread_group_order"), &Node::get_process_thread_group_order); | 
|---|
| 3316 |  | 
|---|
| 3317 | ClassDB::bind_method(D_METHOD( "set_display_folded", "fold"), &Node::set_display_folded); | 
|---|
| 3318 | ClassDB::bind_method(D_METHOD( "is_displayed_folded"), &Node::is_displayed_folded); | 
|---|
| 3319 |  | 
|---|
| 3320 | ClassDB::bind_method(D_METHOD( "set_process_internal", "enable"), &Node::set_process_internal); | 
|---|
| 3321 | ClassDB::bind_method(D_METHOD( "is_processing_internal"), &Node::is_processing_internal); | 
|---|
| 3322 |  | 
|---|
| 3323 | ClassDB::bind_method(D_METHOD( "set_physics_process_internal", "enable"), &Node::set_physics_process_internal); | 
|---|
| 3324 | ClassDB::bind_method(D_METHOD( "is_physics_processing_internal"), &Node::is_physics_processing_internal); | 
|---|
| 3325 |  | 
|---|
| 3326 | ClassDB::bind_method(D_METHOD( "get_window"), &Node::get_window); | 
|---|
| 3327 | ClassDB::bind_method(D_METHOD( "get_last_exclusive_window"), &Node::get_last_exclusive_window); | 
|---|
| 3328 | ClassDB::bind_method(D_METHOD( "get_tree"), &Node::get_tree); | 
|---|
| 3329 | ClassDB::bind_method(D_METHOD( "create_tween"), &Node::create_tween); | 
|---|
| 3330 |  | 
|---|
| 3331 | ClassDB::bind_method(D_METHOD( "duplicate", "flags"), &Node::duplicate, DEFVAL(DUPLICATE_USE_INSTANTIATION | DUPLICATE_SIGNALS | DUPLICATE_GROUPS | DUPLICATE_SCRIPTS)); | 
|---|
| 3332 | ClassDB::bind_method(D_METHOD( "replace_by", "node", "keep_groups"), &Node::replace_by, DEFVAL(false)); | 
|---|
| 3333 |  | 
|---|
| 3334 | ClassDB::bind_method(D_METHOD( "set_scene_instance_load_placeholder", "load_placeholder"), &Node::set_scene_instance_load_placeholder); | 
|---|
| 3335 | ClassDB::bind_method(D_METHOD( "get_scene_instance_load_placeholder"), &Node::get_scene_instance_load_placeholder); | 
|---|
| 3336 | ClassDB::bind_method(D_METHOD( "set_editable_instance", "node", "is_editable"), &Node::set_editable_instance); | 
|---|
| 3337 | ClassDB::bind_method(D_METHOD( "is_editable_instance", "node"), &Node::is_editable_instance); | 
|---|
| 3338 |  | 
|---|
| 3339 | ClassDB::bind_method(D_METHOD( "get_viewport"), &Node::get_viewport); | 
|---|
| 3340 |  | 
|---|
| 3341 | ClassDB::bind_method(D_METHOD( "queue_free"), &Node::queue_free); | 
|---|
| 3342 |  | 
|---|
| 3343 | ClassDB::bind_method(D_METHOD( "request_ready"), &Node::request_ready); | 
|---|
| 3344 | ClassDB::bind_method(D_METHOD( "is_node_ready"), &Node::is_ready); | 
|---|
| 3345 |  | 
|---|
| 3346 | ClassDB::bind_method(D_METHOD( "set_multiplayer_authority", "id", "recursive"), &Node::set_multiplayer_authority, DEFVAL(true)); | 
|---|
| 3347 | ClassDB::bind_method(D_METHOD( "get_multiplayer_authority"), &Node::get_multiplayer_authority); | 
|---|
| 3348 |  | 
|---|
| 3349 | ClassDB::bind_method(D_METHOD( "is_multiplayer_authority"), &Node::is_multiplayer_authority); | 
|---|
| 3350 |  | 
|---|
| 3351 | ClassDB::bind_method(D_METHOD( "get_multiplayer"), &Node::get_multiplayer); | 
|---|
| 3352 | ClassDB::bind_method(D_METHOD( "rpc_config", "method", "config"), &Node::rpc_config); | 
|---|
| 3353 |  | 
|---|
| 3354 | ClassDB::bind_method(D_METHOD( "set_editor_description", "editor_description"), &Node::set_editor_description); | 
|---|
| 3355 | ClassDB::bind_method(D_METHOD( "get_editor_description"), &Node::get_editor_description); | 
|---|
| 3356 |  | 
|---|
| 3357 | ClassDB::bind_method(D_METHOD( "_set_import_path", "import_path"), &Node::set_import_path); | 
|---|
| 3358 | ClassDB::bind_method(D_METHOD( "_get_import_path"), &Node::get_import_path); | 
|---|
| 3359 |  | 
|---|
| 3360 | ClassDB::bind_method(D_METHOD( "set_unique_name_in_owner", "enable"), &Node::set_unique_name_in_owner); | 
|---|
| 3361 | ClassDB::bind_method(D_METHOD( "is_unique_name_in_owner"), &Node::is_unique_name_in_owner); | 
|---|
| 3362 |  | 
|---|
| 3363 | #ifdef TOOLS_ENABLED | 
|---|
| 3364 | ClassDB::bind_method(D_METHOD( "_set_property_pinned", "property", "pinned"), &Node::set_property_pinned); | 
|---|
| 3365 | #endif | 
|---|
| 3366 |  | 
|---|
| 3367 | ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "_import_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_import_path", "_get_import_path"); | 
|---|
| 3368 |  | 
|---|
| 3369 | { | 
|---|
| 3370 | MethodInfo mi; | 
|---|
| 3371 |  | 
|---|
| 3372 | mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "method")); | 
|---|
| 3373 |  | 
|---|
| 3374 | mi.name = "rpc"; | 
|---|
| 3375 | ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "rpc", &Node::_rpc_bind, mi); | 
|---|
| 3376 |  | 
|---|
| 3377 | mi.arguments.push_front(PropertyInfo(Variant::INT, "peer_id")); | 
|---|
| 3378 |  | 
|---|
| 3379 | mi.name = "rpc_id"; | 
|---|
| 3380 | ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "rpc_id", &Node::_rpc_id_bind, mi); | 
|---|
| 3381 | } | 
|---|
| 3382 |  | 
|---|
| 3383 | ClassDB::bind_method(D_METHOD( "update_configuration_warnings"), &Node::update_configuration_warnings); | 
|---|
| 3384 |  | 
|---|
| 3385 | { | 
|---|
| 3386 | MethodInfo mi; | 
|---|
| 3387 | mi.name = "call_deferred_thread_group"; | 
|---|
| 3388 | mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "method")); | 
|---|
| 3389 |  | 
|---|
| 3390 | ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "call_deferred_thread_group", &Node::_call_deferred_thread_group_bind, mi, varray(), false); | 
|---|
| 3391 | } | 
|---|
| 3392 | ClassDB::bind_method(D_METHOD( "set_deferred_thread_group", "property", "value"), &Node::set_deferred_thread_group); | 
|---|
| 3393 | ClassDB::bind_method(D_METHOD( "notify_deferred_thread_group", "what"), &Node::notify_deferred_thread_group); | 
|---|
| 3394 |  | 
|---|
| 3395 | { | 
|---|
| 3396 | MethodInfo mi; | 
|---|
| 3397 | mi.name = "call_thread_safe"; | 
|---|
| 3398 | mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "method")); | 
|---|
| 3399 |  | 
|---|
| 3400 | ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "call_thread_safe", &Node::_call_thread_safe_bind, mi, varray(), false); | 
|---|
| 3401 | } | 
|---|
| 3402 | ClassDB::bind_method(D_METHOD( "set_thread_safe", "property", "value"), &Node::set_thread_safe); | 
|---|
| 3403 | ClassDB::bind_method(D_METHOD( "notify_thread_safe", "what"), &Node::notify_thread_safe); | 
|---|
| 3404 |  | 
|---|
| 3405 | BIND_CONSTANT(NOTIFICATION_ENTER_TREE); | 
|---|
| 3406 | BIND_CONSTANT(NOTIFICATION_EXIT_TREE); | 
|---|
| 3407 | BIND_CONSTANT(NOTIFICATION_MOVED_IN_PARENT); | 
|---|
| 3408 | BIND_CONSTANT(NOTIFICATION_READY); | 
|---|
| 3409 | BIND_CONSTANT(NOTIFICATION_PAUSED); | 
|---|
| 3410 | BIND_CONSTANT(NOTIFICATION_UNPAUSED); | 
|---|
| 3411 | BIND_CONSTANT(NOTIFICATION_PHYSICS_PROCESS); | 
|---|
| 3412 | BIND_CONSTANT(NOTIFICATION_PROCESS); | 
|---|
| 3413 | BIND_CONSTANT(NOTIFICATION_PARENTED); | 
|---|
| 3414 | BIND_CONSTANT(NOTIFICATION_UNPARENTED); | 
|---|
| 3415 | BIND_CONSTANT(NOTIFICATION_SCENE_INSTANTIATED); | 
|---|
| 3416 | BIND_CONSTANT(NOTIFICATION_DRAG_BEGIN); | 
|---|
| 3417 | BIND_CONSTANT(NOTIFICATION_DRAG_END); | 
|---|
| 3418 | BIND_CONSTANT(NOTIFICATION_PATH_RENAMED); | 
|---|
| 3419 | BIND_CONSTANT(NOTIFICATION_CHILD_ORDER_CHANGED); | 
|---|
| 3420 | BIND_CONSTANT(NOTIFICATION_INTERNAL_PROCESS); | 
|---|
| 3421 | BIND_CONSTANT(NOTIFICATION_INTERNAL_PHYSICS_PROCESS); | 
|---|
| 3422 | BIND_CONSTANT(NOTIFICATION_POST_ENTER_TREE); | 
|---|
| 3423 | BIND_CONSTANT(NOTIFICATION_DISABLED); | 
|---|
| 3424 | BIND_CONSTANT(NOTIFICATION_ENABLED); | 
|---|
| 3425 | BIND_CONSTANT(NOTIFICATION_NODE_RECACHE_REQUESTED); | 
|---|
| 3426 |  | 
|---|
| 3427 | BIND_CONSTANT(NOTIFICATION_EDITOR_PRE_SAVE); | 
|---|
| 3428 | BIND_CONSTANT(NOTIFICATION_EDITOR_POST_SAVE); | 
|---|
| 3429 |  | 
|---|
| 3430 | BIND_CONSTANT(NOTIFICATION_WM_MOUSE_ENTER); | 
|---|
| 3431 | BIND_CONSTANT(NOTIFICATION_WM_MOUSE_EXIT); | 
|---|
| 3432 | BIND_CONSTANT(NOTIFICATION_WM_WINDOW_FOCUS_IN); | 
|---|
| 3433 | BIND_CONSTANT(NOTIFICATION_WM_WINDOW_FOCUS_OUT); | 
|---|
| 3434 | BIND_CONSTANT(NOTIFICATION_WM_CLOSE_REQUEST); | 
|---|
| 3435 | BIND_CONSTANT(NOTIFICATION_WM_GO_BACK_REQUEST); | 
|---|
| 3436 | BIND_CONSTANT(NOTIFICATION_WM_SIZE_CHANGED); | 
|---|
| 3437 | BIND_CONSTANT(NOTIFICATION_WM_DPI_CHANGE); | 
|---|
| 3438 | BIND_CONSTANT(NOTIFICATION_VP_MOUSE_ENTER); | 
|---|
| 3439 | BIND_CONSTANT(NOTIFICATION_VP_MOUSE_EXIT); | 
|---|
| 3440 | BIND_CONSTANT(NOTIFICATION_OS_MEMORY_WARNING); | 
|---|
| 3441 | BIND_CONSTANT(NOTIFICATION_TRANSLATION_CHANGED); | 
|---|
| 3442 | BIND_CONSTANT(NOTIFICATION_WM_ABOUT); | 
|---|
| 3443 | BIND_CONSTANT(NOTIFICATION_CRASH); | 
|---|
| 3444 | BIND_CONSTANT(NOTIFICATION_OS_IME_UPDATE); | 
|---|
| 3445 | BIND_CONSTANT(NOTIFICATION_APPLICATION_RESUMED); | 
|---|
| 3446 | BIND_CONSTANT(NOTIFICATION_APPLICATION_PAUSED); | 
|---|
| 3447 | BIND_CONSTANT(NOTIFICATION_APPLICATION_FOCUS_IN); | 
|---|
| 3448 | BIND_CONSTANT(NOTIFICATION_APPLICATION_FOCUS_OUT); | 
|---|
| 3449 | BIND_CONSTANT(NOTIFICATION_TEXT_SERVER_CHANGED); | 
|---|
| 3450 |  | 
|---|
| 3451 | BIND_ENUM_CONSTANT(PROCESS_MODE_INHERIT); | 
|---|
| 3452 | BIND_ENUM_CONSTANT(PROCESS_MODE_PAUSABLE); | 
|---|
| 3453 | BIND_ENUM_CONSTANT(PROCESS_MODE_WHEN_PAUSED); | 
|---|
| 3454 | BIND_ENUM_CONSTANT(PROCESS_MODE_ALWAYS); | 
|---|
| 3455 | BIND_ENUM_CONSTANT(PROCESS_MODE_DISABLED); | 
|---|
| 3456 |  | 
|---|
| 3457 | BIND_ENUM_CONSTANT(PROCESS_THREAD_GROUP_INHERIT); | 
|---|
| 3458 | BIND_ENUM_CONSTANT(PROCESS_THREAD_GROUP_MAIN_THREAD); | 
|---|
| 3459 | BIND_ENUM_CONSTANT(PROCESS_THREAD_GROUP_SUB_THREAD); | 
|---|
| 3460 |  | 
|---|
| 3461 | BIND_BITFIELD_FLAG(FLAG_PROCESS_THREAD_MESSAGES); | 
|---|
| 3462 | BIND_BITFIELD_FLAG(FLAG_PROCESS_THREAD_MESSAGES_PHYSICS); | 
|---|
| 3463 | BIND_BITFIELD_FLAG(FLAG_PROCESS_THREAD_MESSAGES_ALL); | 
|---|
| 3464 |  | 
|---|
| 3465 | BIND_ENUM_CONSTANT(DUPLICATE_SIGNALS); | 
|---|
| 3466 | BIND_ENUM_CONSTANT(DUPLICATE_GROUPS); | 
|---|
| 3467 | BIND_ENUM_CONSTANT(DUPLICATE_SCRIPTS); | 
|---|
| 3468 | BIND_ENUM_CONSTANT(DUPLICATE_USE_INSTANTIATION); | 
|---|
| 3469 |  | 
|---|
| 3470 | BIND_ENUM_CONSTANT(INTERNAL_MODE_DISABLED); | 
|---|
| 3471 | BIND_ENUM_CONSTANT(INTERNAL_MODE_FRONT); | 
|---|
| 3472 | BIND_ENUM_CONSTANT(INTERNAL_MODE_BACK); | 
|---|
| 3473 |  | 
|---|
| 3474 | ADD_SIGNAL(MethodInfo( "ready")); | 
|---|
| 3475 | ADD_SIGNAL(MethodInfo( "renamed")); | 
|---|
| 3476 | ADD_SIGNAL(MethodInfo( "tree_entered")); | 
|---|
| 3477 | ADD_SIGNAL(MethodInfo( "tree_exiting")); | 
|---|
| 3478 | ADD_SIGNAL(MethodInfo( "tree_exited")); | 
|---|
| 3479 | ADD_SIGNAL(MethodInfo( "child_entered_tree", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT, "Node"))); | 
|---|
| 3480 | ADD_SIGNAL(MethodInfo( "child_exiting_tree", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT, "Node"))); | 
|---|
| 3481 |  | 
|---|
| 3482 | ADD_SIGNAL(MethodInfo( "child_order_changed")); | 
|---|
| 3483 | ADD_SIGNAL(MethodInfo( "replacing_by", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT, "Node"))); | 
|---|
| 3484 |  | 
|---|
| 3485 | ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_name", "get_name"); | 
|---|
| 3486 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "unique_name_in_owner", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_unique_name_in_owner", "is_unique_name_in_owner"); | 
|---|
| 3487 | ADD_PROPERTY(PropertyInfo(Variant::STRING, "scene_file_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_scene_file_path", "get_scene_file_path"); | 
|---|
| 3488 | ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "owner", PROPERTY_HINT_RESOURCE_TYPE, "Node", PROPERTY_USAGE_NONE), "set_owner", "get_owner"); | 
|---|
| 3489 | ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "multiplayer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", PROPERTY_USAGE_NONE), "", "get_multiplayer"); | 
|---|
| 3490 |  | 
|---|
| 3491 | ADD_GROUP( "Process", "process_"); | 
|---|
| 3492 | ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Inherit,Pausable,When Paused,Always,Disabled"), "set_process_mode", "get_process_mode"); | 
|---|
| 3493 | ADD_PROPERTY(PropertyInfo(Variant::INT, "process_priority"), "set_process_priority", "get_process_priority"); | 
|---|
| 3494 | ADD_PROPERTY(PropertyInfo(Variant::INT, "process_physics_priority"), "set_physics_process_priority", "get_physics_process_priority"); | 
|---|
| 3495 | ADD_SUBGROUP( "Thread Group", "process_thread"); | 
|---|
| 3496 | ADD_PROPERTY(PropertyInfo(Variant::INT, "process_thread_group", PROPERTY_HINT_ENUM, "Inherit,Main Thread,Sub Thread"), "set_process_thread_group", "get_process_thread_group"); | 
|---|
| 3497 | ADD_PROPERTY(PropertyInfo(Variant::INT, "process_thread_group_order"), "set_process_thread_group_order", "get_process_thread_group_order"); | 
|---|
| 3498 | ADD_PROPERTY(PropertyInfo(Variant::INT, "process_thread_messages", PROPERTY_HINT_FLAGS, "Process,Physics Process"), "set_process_thread_messages", "get_process_thread_messages"); | 
|---|
| 3499 |  | 
|---|
| 3500 | ADD_GROUP( "Editor Description", "editor_"); | 
|---|
| 3501 | ADD_PROPERTY(PropertyInfo(Variant::STRING, "editor_description", PROPERTY_HINT_MULTILINE_TEXT), "set_editor_description", "get_editor_description"); | 
|---|
| 3502 |  | 
|---|
| 3503 | GDVIRTUAL_BIND(_process, "delta"); | 
|---|
| 3504 | GDVIRTUAL_BIND(_physics_process, "delta"); | 
|---|
| 3505 | GDVIRTUAL_BIND(_enter_tree); | 
|---|
| 3506 | GDVIRTUAL_BIND(_exit_tree); | 
|---|
| 3507 | GDVIRTUAL_BIND(_ready); | 
|---|
| 3508 | GDVIRTUAL_BIND(_get_configuration_warnings); | 
|---|
| 3509 | GDVIRTUAL_BIND(_input, "event"); | 
|---|
| 3510 | GDVIRTUAL_BIND(_shortcut_input, "event"); | 
|---|
| 3511 | GDVIRTUAL_BIND(_unhandled_input, "event"); | 
|---|
| 3512 | GDVIRTUAL_BIND(_unhandled_key_input, "event"); | 
|---|
| 3513 | } | 
|---|
| 3514 |  | 
|---|
| 3515 | String Node::_get_name_num_separator() { | 
|---|
| 3516 | switch (GLOBAL_GET( "editor/naming/node_name_num_separator").operator int()) { | 
|---|
| 3517 | case 0: | 
|---|
| 3518 | return ""; | 
|---|
| 3519 | case 1: | 
|---|
| 3520 | return " "; | 
|---|
| 3521 | case 2: | 
|---|
| 3522 | return "_"; | 
|---|
| 3523 | case 3: | 
|---|
| 3524 | return "-"; | 
|---|
| 3525 | } | 
|---|
| 3526 | return " "; | 
|---|
| 3527 | } | 
|---|
| 3528 |  | 
|---|
| 3529 | Node::Node() { | 
|---|
| 3530 | orphan_node_count++; | 
|---|
| 3531 | } | 
|---|
| 3532 |  | 
|---|
| 3533 | Node::~Node() { | 
|---|
| 3534 | data.grouped.clear(); | 
|---|
| 3535 | data.owned.clear(); | 
|---|
| 3536 | data.children.clear(); | 
|---|
| 3537 | data.children_cache.clear(); | 
|---|
| 3538 |  | 
|---|
| 3539 | ERR_FAIL_COND(data.parent); | 
|---|
| 3540 | ERR_FAIL_COND(data.children_cache.size()); | 
|---|
| 3541 |  | 
|---|
| 3542 | orphan_node_count--; | 
|---|
| 3543 | } | 
|---|
| 3544 |  | 
|---|
| 3545 | //////////////////////////////// | 
|---|
| 3546 | // Multithreaded locked version of Object functions. | 
|---|
| 3547 |  | 
|---|
| 3548 | #ifdef DEBUG_ENABLED | 
|---|
| 3549 |  | 
|---|
| 3550 | void Node::set_script(const Variant &p_script) { | 
|---|
| 3551 | ERR_THREAD_GUARD; | 
|---|
| 3552 | Object::set_script(p_script); | 
|---|
| 3553 | } | 
|---|
| 3554 |  | 
|---|
| 3555 | Variant Node::get_script() const { | 
|---|
| 3556 | ERR_THREAD_GUARD_V(Variant()); | 
|---|
| 3557 | return Object::get_script(); | 
|---|
| 3558 | } | 
|---|
| 3559 |  | 
|---|
| 3560 | bool Node::has_meta(const StringName &p_name) const { | 
|---|
| 3561 | ERR_THREAD_GUARD_V(false); | 
|---|
| 3562 | return Object::has_meta(p_name); | 
|---|
| 3563 | } | 
|---|
| 3564 |  | 
|---|
| 3565 | void Node::set_meta(const StringName &p_name, const Variant &p_value) { | 
|---|
| 3566 | ERR_THREAD_GUARD; | 
|---|
| 3567 | Object::set_meta(p_name, p_value); | 
|---|
| 3568 | } | 
|---|
| 3569 |  | 
|---|
| 3570 | void Node::remove_meta(const StringName &p_name) { | 
|---|
| 3571 | ERR_THREAD_GUARD; | 
|---|
| 3572 | Object::remove_meta(p_name); | 
|---|
| 3573 | } | 
|---|
| 3574 |  | 
|---|
| 3575 | Variant Node::get_meta(const StringName &p_name, const Variant &p_default) const { | 
|---|
| 3576 | ERR_THREAD_GUARD_V(Variant()); | 
|---|
| 3577 | return Object::get_meta(p_name, p_default); | 
|---|
| 3578 | } | 
|---|
| 3579 |  | 
|---|
| 3580 | void Node::get_meta_list(List<StringName> *p_list) const { | 
|---|
| 3581 | ERR_THREAD_GUARD; | 
|---|
| 3582 | Object::get_meta_list(p_list); | 
|---|
| 3583 | } | 
|---|
| 3584 |  | 
|---|
| 3585 | Error Node::emit_signalp(const StringName &p_name, const Variant **p_args, int p_argcount) { | 
|---|
| 3586 | ERR_THREAD_GUARD_V(ERR_INVALID_PARAMETER); | 
|---|
| 3587 | return Object::emit_signalp(p_name, p_args, p_argcount); | 
|---|
| 3588 | } | 
|---|
| 3589 |  | 
|---|
| 3590 | bool Node::has_signal(const StringName &p_name) const { | 
|---|
| 3591 | ERR_THREAD_GUARD_V(false); | 
|---|
| 3592 | return Object::has_signal(p_name); | 
|---|
| 3593 | } | 
|---|
| 3594 |  | 
|---|
| 3595 | void Node::get_signal_list(List<MethodInfo> *p_signals) const { | 
|---|
| 3596 | ERR_THREAD_GUARD; | 
|---|
| 3597 | Object::get_signal_list(p_signals); | 
|---|
| 3598 | } | 
|---|
| 3599 |  | 
|---|
| 3600 | void Node::get_signal_connection_list(const StringName &p_signal, List<Connection> *p_connections) const { | 
|---|
| 3601 | ERR_THREAD_GUARD; | 
|---|
| 3602 | Object::get_signal_connection_list(p_signal, p_connections); | 
|---|
| 3603 | } | 
|---|
| 3604 |  | 
|---|
| 3605 | void Node::get_all_signal_connections(List<Connection> *p_connections) const { | 
|---|
| 3606 | ERR_THREAD_GUARD; | 
|---|
| 3607 | Object::get_all_signal_connections(p_connections); | 
|---|
| 3608 | } | 
|---|
| 3609 |  | 
|---|
| 3610 | int Node::get_persistent_signal_connection_count() const { | 
|---|
| 3611 | ERR_THREAD_GUARD_V(0); | 
|---|
| 3612 | return Object::get_persistent_signal_connection_count(); | 
|---|
| 3613 | } | 
|---|
| 3614 |  | 
|---|
| 3615 | void Node::get_signals_connected_to_this(List<Connection> *p_connections) const { | 
|---|
| 3616 | ERR_THREAD_GUARD; | 
|---|
| 3617 | Object::get_signals_connected_to_this(p_connections); | 
|---|
| 3618 | } | 
|---|
| 3619 |  | 
|---|
| 3620 | Error Node::connect(const StringName &p_signal, const Callable &p_callable, uint32_t p_flags) { | 
|---|
| 3621 | ERR_THREAD_GUARD_V(ERR_INVALID_PARAMETER); | 
|---|
| 3622 | return Object::connect(p_signal, p_callable, p_flags); | 
|---|
| 3623 | } | 
|---|
| 3624 |  | 
|---|
| 3625 | void Node::disconnect(const StringName &p_signal, const Callable &p_callable) { | 
|---|
| 3626 | ERR_THREAD_GUARD; | 
|---|
| 3627 | Object::disconnect(p_signal, p_callable); | 
|---|
| 3628 | } | 
|---|
| 3629 |  | 
|---|
| 3630 | bool Node::is_connected(const StringName &p_signal, const Callable &p_callable) const { | 
|---|
| 3631 | ERR_THREAD_GUARD_V(false); | 
|---|
| 3632 | return Object::is_connected(p_signal, p_callable); | 
|---|
| 3633 | } | 
|---|
| 3634 |  | 
|---|
| 3635 | #endif | 
|---|
| 3636 |  | 
|---|