summaryrefslogtreecommitdiffstats
path: root/scene/main/node.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'scene/main/node.cpp')
-rw-r--r--scene/main/node.cpp253
1 files changed, 195 insertions, 58 deletions
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 906c397b5c..11c200064e 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -29,6 +29,7 @@
/**************************************************************************/
#include "node.h"
+#include "node.compat.inc"
#include "core/config/project_settings.h"
#include "core/core_string_names.h"
@@ -99,6 +100,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 +404,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 +546,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 +862,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;
@@ -1679,23 +1756,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 +1891,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) {
@@ -2737,24 +2805,6 @@ 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;
- }
- }
current_node->set(name, value);
}
}
@@ -2771,6 +2821,8 @@ Node *Node::duplicate(int p_flags) const {
_duplicate_signals(this, dupe);
}
+ _duplicate_properties_node(this, this, dupe);
+
return dupe;
}
@@ -2792,6 +2844,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 +2898,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
@@ -2914,7 +3006,7 @@ static void find_owned_by(Node *p_by, Node *p_node, List<Node *> *p_owned) {
}
}
-void Node::replace_by(Node *p_node, bool p_keep_groups) {
+void Node::replace_by(Node *p_node, bool p_keep_groups, bool p_keep_children) {
ERR_THREAD_GUARD
ERR_FAIL_NULL(p_node);
ERR_FAIL_COND(p_node->data.parent);
@@ -2935,13 +3027,13 @@ void Node::replace_by(Node *p_node, bool p_keep_groups) {
_replace_connections_target(p_node);
if (data.owner) {
- for (int i = 0; i < get_child_count(); i++) {
- find_owned_by(data.owner, get_child(i), &owned_by_owner);
+ if (p_keep_children) {
+ for (int i = 0; i < get_child_count(); i++) {
+ find_owned_by(data.owner, get_child(i), &owned_by_owner);
+ }
}
-
_clean_up_owner();
}
-
Node *parent = data.parent;
int index_in_parent = get_index(false);
@@ -2953,31 +3045,33 @@ void Node::replace_by(Node *p_node, bool p_keep_groups) {
emit_signal(SNAME("replacing_by"), p_node);
- while (get_child_count()) {
- Node *child = get_child(0);
- remove_child(child);
- if (!child->is_owned_by_parent()) {
- // add the custom children to the p_node
- Node *child_owner = child->get_owner() == this ? p_node : child->get_owner();
- child->set_owner(nullptr);
- p_node->add_child(child);
- child->set_owner(child_owner);
+ if (p_keep_children) {
+ while (get_child_count()) {
+ Node *child = get_child(0);
+ remove_child(child);
+ if (!child->is_owned_by_parent()) {
+ // add the custom children to the p_node
+ Node *child_owner = child->get_owner() == this ? p_node : child->get_owner();
+ child->set_owner(nullptr);
+ p_node->add_child(child);
+ child->set_owner(child_owner);
+ }
}
- }
- p_node->set_owner(owner);
- for (Node *E : owned) {
- if (E->data.owner != p_node) {
- E->set_owner(p_node);
+ for (Node *E : owned) {
+ if (E->data.owner != p_node) {
+ E->set_owner(p_node);
+ }
}
- }
- for (Node *E : owned_by_owner) {
- if (E->data.owner != owner) {
- E->set_owner(owner);
+ for (Node *E : owned_by_owner) {
+ if (E->data.owner != owner) {
+ E->set_owner(owner);
+ }
}
}
+ p_node->set_owner(owner);
p_node->set_scene_file_path(get_scene_file_path());
}
@@ -3489,6 +3583,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);
@@ -3498,7 +3598,7 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("create_tween"), &Node::create_tween);
ClassDB::bind_method(D_METHOD("duplicate", "flags"), &Node::duplicate, DEFVAL(DUPLICATE_USE_INSTANTIATION | DUPLICATE_SIGNALS | DUPLICATE_GROUPS | DUPLICATE_SCRIPTS));
- ClassDB::bind_method(D_METHOD("replace_by", "node", "keep_groups"), &Node::replace_by, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("replace_by", "node", "keep_groups", "keep_children"), &Node::replace_by, DEFVAL(false), DEFVAL(true));
ClassDB::bind_method(D_METHOD("set_scene_instance_load_placeholder", "load_placeholder"), &Node::set_scene_instance_load_placeholder);
ClassDB::bind_method(D_METHOD("get_scene_instance_load_placeholder"), &Node::get_scene_instance_load_placeholder);
@@ -3594,6 +3694,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 +3734,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 +3779,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 +3816,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() {