From 6b3bab6e54e7993296648c6dfdb2b42ef6195da8 Mon Sep 17 00:00:00 2001 From: Marcel Admiraal Date: Sat, 26 Dec 2020 13:54:41 +0000 Subject: [PATCH] Add signal to inform joint that body has exited tree --- modules/bullet/space_bullet.cpp | 2 +- scene/2d/joints_2d.cpp | 45 +++++++++++++++++++++++++++-- scene/2d/joints_2d.h | 2 ++ scene/3d/physics_joint.cpp | 50 +++++++++++++++++++++++++++++++-- scene/3d/physics_joint.h | 2 ++ 5 files changed, 95 insertions(+), 6 deletions(-) diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp index 9513c210378..a29b0d0ceea 100644 --- a/modules/bullet/space_bullet.cpp +++ b/modules/bullet/space_bullet.cpp @@ -502,7 +502,7 @@ void SpaceBullet::remove_rigid_body(RigidBodyBullet *p_body) { int constraints = btBody->getNumConstraintRefs(); if (constraints > 0) { - WARN_PRINT("A body connected to joints was removed. Ensure bodies are disconnected from joints before removing them."); + ERR_PRINT("A body connected to joints was removed."); for (int i = 0; i < constraints; i++) { dynamicsWorld->removeConstraint(btBody->getConstraintRef(i)); } diff --git a/scene/2d/joints_2d.cpp b/scene/2d/joints_2d.cpp index 9b8400b7226..fdb97663454 100644 --- a/scene/2d/joints_2d.cpp +++ b/scene/2d/joints_2d.cpp @@ -32,8 +32,36 @@ #include "core/engine.h" #include "physics_body_2d.h" +#include "scene/scene_string_names.h" #include "servers/physics_2d_server.h" +void Joint2D::_disconnect_signals() { + + Node *node_a = get_node_or_null(a); + PhysicsBody2D *body_a = Object::cast_to(node_a); + if (body_a) + body_a->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree); + + Node *node_b = get_node_or_null(b); + PhysicsBody2D *body_b = Object::cast_to(node_b); + if (body_b) + body_b->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree); +} + +void Joint2D::_body_exit_tree(const ObjectID &p_body_id) { + + _disconnect_signals(); + Object *object = ObjectDB::get_instance(p_body_id); + PhysicsBody2D *body = Object::cast_to(object); + ERR_FAIL_NULL(body); + RID body_rid = body->get_rid(); + if (ba == body_rid) + a = NodePath(); + if (bb == body_rid) + b = NodePath(); + _update_joint(); +} + void Joint2D::_update_joint(bool p_only_free) { if (joint.is_valid()) { @@ -51,8 +79,8 @@ void Joint2D::_update_joint(bool p_only_free) { return; } - Node *node_a = has_node(get_node_a()) ? get_node(get_node_a()) : (Node *)NULL; - Node *node_b = has_node(get_node_b()) ? get_node(get_node_b()) : (Node *)NULL; + Node *node_a = get_node_or_null(a); + Node *node_b = get_node_or_null(b); PhysicsBody2D *body_a = Object::cast_to(node_a); PhysicsBody2D *body_b = Object::cast_to(node_b); @@ -107,6 +135,9 @@ void Joint2D::_update_joint(bool p_only_free) { ba = body_a->get_rid(); bb = body_b->get_rid(); + body_a->connect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree, make_binds(body_a->get_instance_id())); + body_b->connect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree, make_binds(body_b->get_instance_id())); + Physics2DServer::get_singleton()->joint_disable_collisions_between_bodies(joint, exclude_from_collision); } @@ -115,6 +146,9 @@ void Joint2D::set_node_a(const NodePath &p_node_a) { if (a == p_node_a) return; + if (joint.is_valid()) + _disconnect_signals(); + a = p_node_a; _update_joint(); } @@ -128,6 +162,10 @@ void Joint2D::set_node_b(const NodePath &p_node_b) { if (b == p_node_b) return; + + if (joint.is_valid()) + _disconnect_signals(); + b = p_node_b; _update_joint(); } @@ -145,6 +183,7 @@ void Joint2D::_notification(int p_what) { } break; case NOTIFICATION_EXIT_TREE: { if (joint.is_valid()) { + _disconnect_signals(); _update_joint(true); } } break; @@ -194,6 +233,8 @@ String Joint2D::get_configuration_warning() const { void Joint2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("_body_exit_tree", "body_rid"), &Joint2D::_body_exit_tree); + ClassDB::bind_method(D_METHOD("set_node_a", "node"), &Joint2D::set_node_a); ClassDB::bind_method(D_METHOD("get_node_a"), &Joint2D::get_node_a); diff --git a/scene/2d/joints_2d.h b/scene/2d/joints_2d.h index 1de53977f64..4d07e711d31 100644 --- a/scene/2d/joints_2d.h +++ b/scene/2d/joints_2d.h @@ -50,6 +50,8 @@ class Joint2D : public Node2D { String warning; protected: + void _disconnect_signals(); + void _body_exit_tree(const ObjectID &p_body_id); void _update_joint(bool p_only_free = false); void _notification(int p_what); diff --git a/scene/3d/physics_joint.cpp b/scene/3d/physics_joint.cpp index 3cef15776db..48ac6088b20 100644 --- a/scene/3d/physics_joint.cpp +++ b/scene/3d/physics_joint.cpp @@ -30,6 +30,35 @@ #include "physics_joint.h" +#include "scene/scene_string_names.h" + +void Joint::_disconnect_signals() { + + Node *node_a = get_node_or_null(a); + PhysicsBody *body_a = Object::cast_to(node_a); + if (body_a) + body_a->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree); + + Node *node_b = get_node_or_null(b); + PhysicsBody *body_b = Object::cast_to(node_b); + if (body_b) + body_b->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree); +} + +void Joint::_body_exit_tree(const ObjectID &p_body_id) { + + _disconnect_signals(); + Object *object = ObjectDB::get_instance(p_body_id); + PhysicsBody *body = Object::cast_to(object); + ERR_FAIL_NULL(body); + RID body_rid = body->get_rid(); + if (ba == body_rid) + a = NodePath(); + if (bb == body_rid) + b = NodePath(); + _update_joint(); +} + void Joint::_update_joint(bool p_only_free) { if (joint.is_valid()) { @@ -47,8 +76,8 @@ void Joint::_update_joint(bool p_only_free) { return; } - Node *node_a = has_node(get_node_a()) ? get_node(get_node_a()) : (Node *)NULL; - Node *node_b = has_node(get_node_b()) ? get_node(get_node_b()) : (Node *)NULL; + Node *node_a = get_node_or_null(a); + Node *node_b = get_node_or_null(b); PhysicsBody *body_a = Object::cast_to(node_a); PhysicsBody *body_b = Object::cast_to(node_b); @@ -97,8 +126,12 @@ void Joint::_update_joint(bool p_only_free) { PhysicsServer::get_singleton()->joint_set_solver_priority(joint, solver_priority); ba = body_a->get_rid(); - if (body_b) + body_a->connect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree, make_binds(body_a->get_instance_id())); + + if (body_b) { bb = body_b->get_rid(); + body_b->connect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree, make_binds(body_b->get_instance_id())); + } PhysicsServer::get_singleton()->joint_disable_collisions_between_bodies(joint, exclude_from_collision); } @@ -108,6 +141,9 @@ void Joint::set_node_a(const NodePath &p_node_a) { if (a == p_node_a) return; + if (joint.is_valid()) + _disconnect_signals(); + a = p_node_a; _update_joint(); } @@ -121,9 +157,14 @@ void Joint::set_node_b(const NodePath &p_node_b) { if (b == p_node_b) return; + + if (joint.is_valid()) + _disconnect_signals(); + b = p_node_b; _update_joint(); } + NodePath Joint::get_node_b() const { return b; @@ -150,6 +191,7 @@ void Joint::_notification(int p_what) { } break; case NOTIFICATION_EXIT_TREE: { if (joint.is_valid()) { + _disconnect_signals(); _update_joint(true); } } break; @@ -185,6 +227,8 @@ String Joint::get_configuration_warning() const { void Joint::_bind_methods() { + ClassDB::bind_method(D_METHOD("_body_exit_tree", "body_rid"), &Joint::_body_exit_tree); + ClassDB::bind_method(D_METHOD("set_node_a", "node"), &Joint::set_node_a); ClassDB::bind_method(D_METHOD("get_node_a"), &Joint::get_node_a); diff --git a/scene/3d/physics_joint.h b/scene/3d/physics_joint.h index 7a57e91b627..f4d60fc64f5 100644 --- a/scene/3d/physics_joint.h +++ b/scene/3d/physics_joint.h @@ -50,6 +50,8 @@ class Joint : public Spatial { String warning; protected: + void _disconnect_signals(); + void _body_exit_tree(const ObjectID &p_body_id); void _update_joint(bool p_only_free = false); void _notification(int p_what);