From 9a9dccbaa26915bfce5343f21092add79de02059 Mon Sep 17 00:00:00 2001 From: lawnjelly Date: Wed, 28 Feb 2024 07:48:13 +0000 Subject: [PATCH] Fix physics on_floor_body crash Physics body previously stored the RID of a collision object and accessed it on the next frame, leading to a crash if the object had been deleted. This PR stores the ObjectID in addition to the RID, and checks the object still exists prior to access. --- scene/3d/physics_body.cpp | 33 +++++++++++++++++++++++---------- scene/3d/physics_body.h | 3 ++- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index 237d6b4fe85..db3a7695ed3 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -1077,9 +1077,17 @@ Vector3 KinematicBody::_move_and_slide_internal(const Vector3 &p_linear_velocity float delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time(); Vector3 current_floor_velocity = floor_velocity; - if (on_floor && on_floor_body.is_valid()) { - // This approach makes sure there is less delay between the actual body velocity and the one we saved. - PhysicsDirectBodyState *bs = PhysicsServer::get_singleton()->body_get_direct_state(on_floor_body); + + if (on_floor && on_floor_body_rid.is_valid()) { + PhysicsDirectBodyState *bs = nullptr; + + // We need to check the on_floor_body still exists before accessing. + // A valid RID is no guarantee that the object has not been deleted. + if (ObjectDB::get_instance(on_floor_body_id)) { + // This approach makes sure there is less delay between the actual body velocity and the one we saved. + bs = PhysicsServer::get_singleton()->body_get_direct_state(on_floor_body_rid); + } + if (bs) { Transform gt = get_global_transform(); Vector3 local_position = gt.origin - bs->get_transform().origin; @@ -1087,7 +1095,8 @@ Vector3 KinematicBody::_move_and_slide_internal(const Vector3 &p_linear_velocity } else { // Body is removed or destroyed, invalidate floor. current_floor_velocity = Vector3(); - on_floor_body = RID(); + on_floor_body_rid = RID(); + on_floor_body_id = ObjectID(); } } @@ -1098,17 +1107,18 @@ Vector3 KinematicBody::_move_and_slide_internal(const Vector3 &p_linear_velocity floor_normal = Vector3(); floor_velocity = Vector3(); - if (current_floor_velocity != Vector3() && on_floor_body.is_valid()) { + if (current_floor_velocity != Vector3() && on_floor_body_rid.is_valid()) { Collision floor_collision; Set exclude; - exclude.insert(on_floor_body); + exclude.insert(on_floor_body_rid); if (move_and_collide(current_floor_velocity * delta, p_infinite_inertia, floor_collision, true, false, false, exclude)) { colliders.push_back(floor_collision); _set_collision_direction(floor_collision, up_direction, p_floor_max_angle); } } - on_floor_body = RID(); + on_floor_body_rid = RID(); + on_floor_body_id = ObjectID(); Vector3 motion = body_velocity * delta; // No sliding on first attempt to keep floor motion stable when possible, @@ -1186,7 +1196,8 @@ Vector3 KinematicBody::_move_and_slide_internal(const Vector3 &p_linear_velocity if (Math::acos(col.normal.dot(up_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { on_floor = true; floor_normal = col.normal; - on_floor_body = col.collider_rid; + on_floor_body_rid = col.collider_rid; + on_floor_body_id = col.collider; floor_velocity = col.collider_vel; if (p_stop_on_slope) { // move and collide may stray the object a bit because of pre un-stucking, @@ -1237,7 +1248,8 @@ void KinematicBody::_set_collision_direction(const Collision &p_collision, const if (Math::acos(p_collision.normal.dot(p_up_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor on_floor = true; floor_normal = p_collision.normal; - on_floor_body = p_collision.collider_rid; + on_floor_body_rid = p_collision.collider_rid; + on_floor_body_id = p_collision.collider; floor_velocity = p_collision.collider_vel; } else if (Math::acos(p_collision.normal.dot(-p_up_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling on_ceiling = true; @@ -1429,7 +1441,8 @@ void KinematicBody::_notification(int p_what) { // Reset move_and_slide() data. on_floor = false; - on_floor_body = RID(); + on_floor_body_rid = RID(); + on_floor_body_id = ObjectID(); on_ceiling = false; on_wall = false; colliders.clear(); diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h index 4f7a674d39e..e31d8782476 100644 --- a/scene/3d/physics_body.h +++ b/scene/3d/physics_body.h @@ -292,7 +292,8 @@ private: Vector3 floor_normal; Vector3 floor_velocity; - RID on_floor_body; + RID on_floor_body_rid; + ObjectID on_floor_body_id; bool on_floor; bool on_ceiling; bool on_wall;