diff options
Diffstat (limited to 'scene/main/node.cpp')
-rw-r--r-- | scene/main/node.cpp | 181 |
1 files changed, 163 insertions, 18 deletions
diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 906c397b5c..142736e388 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -99,6 +99,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."); @@ -395,6 +403,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 +545,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 +861,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; @@ -2737,25 +2813,9 @@ Node *Node::_duplicate(int p_flags, HashMap<const Node *, Node *> *r_duplimap) c } } 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; - } + if (value.get_type() != Variant::OBJECT && (value.get_type() != Variant::ARRAY || static_cast<Array>(value).get_typed_builtin() != Variant::OBJECT)) { + current_node->set(name, value); } - current_node->set(name, value); } } } @@ -2771,6 +2831,8 @@ Node *Node::duplicate(int p_flags) const { _duplicate_signals(this, dupe); } + _duplicate_properties_node(this, this, dupe); + return dupe; } @@ -2792,6 +2854,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_node(this, this, dupe); + return dupe; } @@ -2844,6 +2908,44 @@ void Node::remap_nested_resources(Ref<Resource> p_resource, const HashMap<Ref<Re } #endif +// Duplicates properties that store a Node. +// This has to be called after nodes have been duplicated since +// only then do we get a full picture of how the duplicated node tree looks like. +void Node::_duplicate_properties_node(const Node *p_root, const Node *p_original, Node *p_copy) const { + List<PropertyInfo> props; + p_copy->get_property_list(&props); + for (const PropertyInfo &E : props) { + if (!(E.usage & PROPERTY_USAGE_STORAGE)) { + continue; + } + String name = E.name; + Variant value = p_original->get(name).duplicate(true); + if (value.get_type() == Variant::OBJECT) { + Node *property_node = Object::cast_to<Node>(value); + if (property_node && (p_root == property_node || p_root->is_ancestor_of(property_node))) { + value = p_copy->get_node_or_null(p_original->get_path_to(property_node)); + p_copy->set(name, 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); + } + } + } + + for (int i = 0; i < p_copy->get_child_count(); i++) { + _duplicate_properties_node(p_root, p_original->get_child(i), p_copy->get_child(i)); + } +} + // 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 @@ -3489,6 +3591,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 +3702,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 +3742,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 +3787,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,Off,On"), "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 +3824,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 = false; + + 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() { |