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.cpp293
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() {