diff options
Diffstat (limited to 'scene/main/node.cpp')
-rw-r--r-- | scene/main/node.cpp | 293 |
1 files changed, 205 insertions, 88 deletions
diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 906c397b5c..884fc6de07 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -31,7 +31,6 @@ #include "node.h" #include "core/config/project_settings.h" -#include "core/core_string_names.h" #include "core/io/resource_loader.h" #include "core/object/message_queue.h" #include "core/object/script_language.h" @@ -42,7 +41,6 @@ #include "scene/main/multiplayer_api.h" #include "scene/main/window.h" #include "scene/resources/packed_scene.h" -#include "scene/scene_string_names.h" #include "viewport.h" #include <stdint.h> @@ -99,6 +97,14 @@ void Node::_notification(int p_notification) { } } + if (data.physics_interpolation_mode == PHYSICS_INTERPOLATION_MODE_INHERIT) { + bool interpolate = true; // Root node default is for interpolation to be on. + if (data.parent) { + interpolate = data.parent->is_physics_interpolated(); + } + _propagate_physics_interpolated(interpolate); + } + // Update auto translate mode. if (data.auto_translate_mode == AUTO_TRANSLATE_MODE_INHERIT && !data.parent) { ERR_PRINT("The root node can't be set to Inherit auto translate mode, reverting to Always instead."); @@ -258,7 +264,7 @@ void Node::_propagate_ready() { if (data.ready_first) { data.ready_first = false; notification(NOTIFICATION_READY); - emit_signal(SceneStringNames::get_singleton()->ready); + emit_signal(SceneStringName(ready)); } } @@ -287,7 +293,7 @@ void Node::_propagate_enter_tree() { GDVIRTUAL_CALL(_enter_tree); - emit_signal(SceneStringNames::get_singleton()->tree_entered); + emit_signal(SceneStringName(tree_entered)); data.tree->node_added(this); @@ -342,7 +348,7 @@ void Node::_propagate_after_exit_tree() { data.blocked--; - emit_signal(SceneStringNames::get_singleton()->tree_exited); + emit_signal(SceneStringName(tree_exited)); } void Node::_propagate_exit_tree() { @@ -364,7 +370,7 @@ void Node::_propagate_exit_tree() { GDVIRTUAL_CALL(_exit_tree); - emit_signal(SceneStringNames::get_singleton()->tree_exiting); + emit_signal(SceneStringName(tree_exiting)); notification(NOTIFICATION_EXIT_TREE, true); if (data.tree) { @@ -395,6 +401,36 @@ void Node::_propagate_exit_tree() { data.depth = -1; } +void Node::_propagate_physics_interpolated(bool p_interpolated) { + switch (data.physics_interpolation_mode) { + case PHYSICS_INTERPOLATION_MODE_INHERIT: + // Keep the parent p_interpolated. + break; + case PHYSICS_INTERPOLATION_MODE_OFF: { + p_interpolated = false; + } break; + case PHYSICS_INTERPOLATION_MODE_ON: { + p_interpolated = true; + } break; + } + + // No change? No need to propagate further. + if (data.physics_interpolated == p_interpolated) { + return; + } + + data.physics_interpolated = p_interpolated; + + // Allow a call to the RenderingServer etc. in derived classes. + _physics_interpolated_changed(); + + data.blocked++; + for (KeyValue<StringName, Node *> &K : data.children) { + K.value->_propagate_physics_interpolated(p_interpolated); + } + data.blocked--; +} + void Node::move_child(Node *p_child, int p_index) { 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)."); ERR_FAIL_NULL(p_child); @@ -507,6 +543,8 @@ void Node::move_child_notify(Node *p_child) { void Node::owner_changed_notify() { } +void Node::_physics_interpolated_changed() {} + void Node::set_physics_process(bool p_process) { ERR_THREAD_GUARD if (data.physics_process == p_process) { @@ -821,6 +859,42 @@ bool Node::_can_process(bool p_paused) const { } } +void Node::set_physics_interpolation_mode(PhysicsInterpolationMode p_mode) { + ERR_THREAD_GUARD + if (data.physics_interpolation_mode == p_mode) { + return; + } + + data.physics_interpolation_mode = p_mode; + + bool interpolate = true; // Default for root node. + + switch (p_mode) { + case PHYSICS_INTERPOLATION_MODE_INHERIT: { + if (is_inside_tree() && data.parent) { + interpolate = data.parent->is_physics_interpolated(); + } + } break; + case PHYSICS_INTERPOLATION_MODE_OFF: { + interpolate = false; + } break; + case PHYSICS_INTERPOLATION_MODE_ON: { + interpolate = true; + } break; + } + + // If swapping from interpolated to non-interpolated, use this as an extra means to cause a reset. + if (is_physics_interpolated() && !interpolate) { + reset_physics_interpolation(); + } + + _propagate_physics_interpolated(interpolate); +} + +void Node::reset_physics_interpolation() { + propagate_notification(NOTIFICATION_RESET_PHYSICS_INTERPOLATION); +} + bool Node::_is_enabled() const { ProcessMode process_mode; @@ -1662,12 +1736,10 @@ Node *Node::get_node_or_null(const NodePath &p_path) const { StringName name = p_path.get_name(i); Node *next = nullptr; - if (name == SceneStringNames::get_singleton()->dot) { // . - + if (name == SNAME(".")) { next = current; - } else if (name == SceneStringNames::get_singleton()->doubledot) { // .. - + } else if (name == SNAME("..")) { if (current == nullptr || !current->data.parent) { return nullptr; } @@ -1679,23 +1751,14 @@ Node *Node::get_node_or_null(const NodePath &p_path) const { } } else if (name.is_node_unique_name()) { - if (current->data.owned_unique_nodes.size()) { - // Has unique nodes in ownership - Node **unique = current->data.owned_unique_nodes.getptr(name); - if (!unique) { - return nullptr; - } - next = *unique; - } else if (current->data.owner) { - Node **unique = current->data.owner->data.owned_unique_nodes.getptr(name); - if (!unique) { - return nullptr; - } - next = *unique; - } else { + Node **unique = current->data.owned_unique_nodes.getptr(name); + if (!unique && current->data.owner) { + unique = current->data.owner->data.owned_unique_nodes.getptr(name); + } + if (!unique) { return nullptr; } - + next = *unique; } else { next = nullptr; const Node *const *node = current->data.children.getptr(name); @@ -1823,7 +1886,7 @@ void Node::reparent(Node *p_parent, bool p_keep_global_transform) { Node *check = to_visit[to_visit.size() - 1]; to_visit.resize(to_visit.size() - 1); - for (int i = 0; i < check->get_child_count(); i++) { + for (int i = 0; i < check->get_child_count(false); i++) { Node *child = check->get_child(i, false); to_visit.push_back(child); if (child->data.owner == owner_temp) { @@ -2600,8 +2663,6 @@ Node *Node::_duplicate(int p_flags, HashMap<const Node *, Node *> *r_duplimap) c node->data.editable_instance = data.editable_instance; } - StringName script_property_name = CoreStringNames::get_singleton()->_script; - List<const Node *> hidden_roots; List<const Node *> node_tree; node_tree.push_front(this); @@ -2703,63 +2764,6 @@ Node *Node::_duplicate(int p_flags, HashMap<const Node *, Node *> *r_duplimap) c parent->move_child(dup, pos); } } - - for (List<const Node *>::Element *N = node_tree.front(); N; N = N->next()) { - Node *current_node = node->get_node(get_path_to(N->get())); - ERR_CONTINUE(!current_node); - - if (p_flags & DUPLICATE_SCRIPTS) { - bool is_valid = false; - Variant scr = N->get()->get(script_property_name, &is_valid); - if (is_valid) { - current_node->set(script_property_name, scr); - } - } - - List<PropertyInfo> plist; - N->get()->get_property_list(&plist); - - for (const PropertyInfo &E : plist) { - if (!(E.usage & PROPERTY_USAGE_STORAGE)) { - continue; - } - String name = E.name; - if (name == script_property_name) { - continue; - } - - Variant value = N->get()->get(name).duplicate(true); - - if (E.usage & PROPERTY_USAGE_ALWAYS_DUPLICATE) { - Resource *res = Object::cast_to<Resource>(value); - if (res) { // Duplicate only if it's a resource - current_node->set(name, res->duplicate()); - } - - } else { - // If property points to a node which is owned by a node we are duplicating, update its path. - if (value.get_type() == Variant::OBJECT) { - Node *property_node = Object::cast_to<Node>(value); - if (property_node && is_ancestor_of(property_node)) { - value = current_node->get_node_or_null(get_path_to(property_node)); - } - } else if (value.get_type() == Variant::ARRAY) { - Array arr = value; - if (arr.get_typed_builtin() == Variant::OBJECT) { - for (int i = 0; i < arr.size(); i++) { - Node *property_node = Object::cast_to<Node>(arr[i]); - if (property_node && is_ancestor_of(property_node)) { - arr[i] = current_node->get_node_or_null(get_path_to(property_node)); - } - } - value = arr; - } - } - current_node->set(name, value); - } - } - } - return node; } @@ -2771,6 +2775,8 @@ Node *Node::duplicate(int p_flags) const { _duplicate_signals(this, dupe); } + _duplicate_properties(this, this, dupe, p_flags); + return dupe; } @@ -2780,7 +2786,8 @@ Node *Node::duplicate_from_editor(HashMap<const Node *, Node *> &r_duplimap) con } Node *Node::duplicate_from_editor(HashMap<const Node *, Node *> &r_duplimap, const HashMap<Ref<Resource>, Ref<Resource>> &p_resource_remap) const { - Node *dupe = _duplicate(DUPLICATE_SIGNALS | DUPLICATE_GROUPS | DUPLICATE_SCRIPTS | DUPLICATE_USE_INSTANTIATION | DUPLICATE_FROM_EDITOR, &r_duplimap); + int flags = DUPLICATE_SIGNALS | DUPLICATE_GROUPS | DUPLICATE_SCRIPTS | DUPLICATE_USE_INSTANTIATION | DUPLICATE_FROM_EDITOR; + Node *dupe = _duplicate(flags, &r_duplimap); // This is used by SceneTreeDock's paste functionality. When pasting to foreign scene, resources are duplicated. if (!p_resource_remap.is_empty()) { @@ -2792,6 +2799,8 @@ Node *Node::duplicate_from_editor(HashMap<const Node *, Node *> &r_duplimap, con // if the emitter node comes later in tree order than the receiver _duplicate_signals(this, dupe); + _duplicate_properties(this, this, dupe, flags); + return dupe; } @@ -2844,6 +2853,70 @@ void Node::remap_nested_resources(Ref<Resource> p_resource, const HashMap<Ref<Re } #endif +// Duplicate node's properties. +// This has to be called after nodes have been duplicated since there might be properties +// of type Node that can be updated properly only if duplicated node tree is complete. +void Node::_duplicate_properties(const Node *p_root, const Node *p_original, Node *p_copy, int p_flags) const { + List<PropertyInfo> props; + p_original->get_property_list(&props); + const StringName &script_property_name = CoreStringName(script); + if (p_flags & DUPLICATE_SCRIPTS) { + bool is_valid = false; + Variant scr = p_original->get(script_property_name, &is_valid); + if (is_valid) { + p_copy->set(script_property_name, scr); + } + } + for (const PropertyInfo &E : props) { + if (!(E.usage & PROPERTY_USAGE_STORAGE)) { + continue; + } + const StringName name = E.name; + + if (name == script_property_name) { + continue; + } + + Variant value = p_original->get(name).duplicate(true); + + if (E.usage & PROPERTY_USAGE_ALWAYS_DUPLICATE) { + Resource *res = Object::cast_to<Resource>(value); + if (res) { // Duplicate only if it's a resource + p_copy->set(name, res->duplicate()); + } + } else { + if (value.get_type() == Variant::OBJECT) { + Node *property_node = Object::cast_to<Node>(value); + Variant out_value = value; + if (property_node && (p_root == property_node || p_root->is_ancestor_of(property_node))) { + out_value = p_copy->get_node_or_null(p_original->get_path_to(property_node)); + } + p_copy->set(name, out_value); + } else if (value.get_type() == Variant::ARRAY) { + Array arr = value; + if (arr.get_typed_builtin() == Variant::OBJECT) { + for (int i = 0; i < arr.size(); i++) { + Node *property_node = Object::cast_to<Node>(arr[i]); + if (property_node && (p_root == property_node || p_root->is_ancestor_of(property_node))) { + arr[i] = p_copy->get_node_or_null(p_original->get_path_to(property_node)); + } + } + value = arr; + p_copy->set(name, value); + } + } else { + p_copy->set(name, value); + } + } + } + + for (int i = 0; i < p_original->get_child_count(); i++) { + Node *copy_child = p_copy->get_child(i); + ERR_FAIL_NULL_MSG(copy_child, "Child node disappeared while duplicating."); + _duplicate_properties(p_root, p_original->get_child(i), copy_child, p_flags); + } +} + // Duplication of signals must happen after all the node descendants have been copied, // because re-targeting of connections from some descendant to another is not possible // if the emitter node comes later in tree order than the receiver @@ -3140,7 +3213,7 @@ void Node::print_orphan_nodes() { ObjectDB::debug_objects(_print_orphan_nodes_routine); for (const KeyValue<ObjectID, List<String>> &E : _print_orphan_nodes_map) { - print_line(itos(E.key) + " - Stray Node: " + E.value[0] + " (Type: " + E.value[1] + ")"); + print_line(itos(E.key) + " - Stray Node: " + E.value.get(0) + " (Type: " + E.value.get(1) + ")"); } // Flush it after use. @@ -3230,7 +3303,7 @@ void Node::update_configuration_warnings() { return; } if (get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root() == this || get_tree()->get_edited_scene_root()->is_ancestor_of(this))) { - get_tree()->emit_signal(SceneStringNames::get_singleton()->node_configuration_warning_changed, this); + get_tree()->emit_signal(SceneStringName(node_configuration_warning_changed), this); } #endif } @@ -3429,6 +3502,7 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("get_node_and_resource", "path"), &Node::_get_node_and_resource); ClassDB::bind_method(D_METHOD("is_inside_tree"), &Node::is_inside_tree); + ClassDB::bind_method(D_METHOD("is_part_of_edited_scene"), &Node::is_part_of_edited_scene); ClassDB::bind_method(D_METHOD("is_ancestor_of", "node"), &Node::is_ancestor_of); ClassDB::bind_method(D_METHOD("is_greater_than", "node"), &Node::is_greater_than); ClassDB::bind_method(D_METHOD("get_path"), &Node::get_path); @@ -3489,6 +3563,12 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("set_physics_process_internal", "enable"), &Node::set_physics_process_internal); ClassDB::bind_method(D_METHOD("is_physics_processing_internal"), &Node::is_physics_processing_internal); + ClassDB::bind_method(D_METHOD("set_physics_interpolation_mode", "mode"), &Node::set_physics_interpolation_mode); + ClassDB::bind_method(D_METHOD("get_physics_interpolation_mode"), &Node::get_physics_interpolation_mode); + ClassDB::bind_method(D_METHOD("is_physics_interpolated"), &Node::is_physics_interpolated); + ClassDB::bind_method(D_METHOD("is_physics_interpolated_and_enabled"), &Node::is_physics_interpolated_and_enabled); + ClassDB::bind_method(D_METHOD("reset_physics_interpolation"), &Node::reset_physics_interpolation); + ClassDB::bind_method(D_METHOD("set_auto_translate_mode", "mode"), &Node::set_auto_translate_mode); ClassDB::bind_method(D_METHOD("get_auto_translate_mode"), &Node::get_auto_translate_mode); @@ -3594,6 +3674,7 @@ void Node::_bind_methods() { BIND_CONSTANT(NOTIFICATION_POST_ENTER_TREE); BIND_CONSTANT(NOTIFICATION_DISABLED); BIND_CONSTANT(NOTIFICATION_ENABLED); + BIND_CONSTANT(NOTIFICATION_RESET_PHYSICS_INTERPOLATION); BIND_CONSTANT(NOTIFICATION_EDITOR_PRE_SAVE); BIND_CONSTANT(NOTIFICATION_EDITOR_POST_SAVE); @@ -3633,6 +3714,10 @@ void Node::_bind_methods() { BIND_BITFIELD_FLAG(FLAG_PROCESS_THREAD_MESSAGES_PHYSICS); BIND_BITFIELD_FLAG(FLAG_PROCESS_THREAD_MESSAGES_ALL); + BIND_ENUM_CONSTANT(PHYSICS_INTERPOLATION_MODE_INHERIT); + BIND_ENUM_CONSTANT(PHYSICS_INTERPOLATION_MODE_ON); + BIND_ENUM_CONSTANT(PHYSICS_INTERPOLATION_MODE_OFF); + BIND_ENUM_CONSTANT(DUPLICATE_SIGNALS); BIND_ENUM_CONSTANT(DUPLICATE_GROUPS); BIND_ENUM_CONSTANT(DUPLICATE_SCRIPTS); @@ -3674,6 +3759,9 @@ void Node::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "process_thread_group_order"), "set_process_thread_group_order", "get_process_thread_group_order"); ADD_PROPERTY(PropertyInfo(Variant::INT, "process_thread_messages", PROPERTY_HINT_FLAGS, "Process,Physics Process"), "set_process_thread_messages", "get_process_thread_messages"); + ADD_GROUP("Physics Interpolation", "physics_interpolation_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "physics_interpolation_mode", PROPERTY_HINT_ENUM, "Inherit,On,Off"), "set_physics_interpolation_mode", "get_physics_interpolation_mode"); + ADD_GROUP("Auto Translate", "auto_translate_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "auto_translate_mode", PROPERTY_HINT_ENUM, "Inherit,Always,Disabled"), "set_auto_translate_mode", "get_auto_translate_mode"); @@ -3708,6 +3796,35 @@ String Node::_get_name_num_separator() { Node::Node() { orphan_node_count++; + + // Default member initializer for bitfield is a C++20 extension, so: + + data.process_mode = PROCESS_MODE_INHERIT; + data.physics_interpolation_mode = PHYSICS_INTERPOLATION_MODE_INHERIT; + + data.physics_process = false; + data.process = false; + + data.physics_process_internal = false; + data.process_internal = false; + + data.input = false; + data.shortcut_input = false; + data.unhandled_input = false; + data.unhandled_key_input = false; + + data.physics_interpolated = true; + + data.parent_owned = false; + data.in_constructor = true; + data.use_placeholder = false; + + data.display_folded = false; + data.editable_instance = false; + + data.inside_tree = false; + data.ready_notified = false; // This is a small hack, so if a node is added during _ready() to the tree, it correctly gets the _ready() notification. + data.ready_first = true; } Node::~Node() { |