Skip to content

Commit

Permalink
Fix errors in CharacterBody when floor is destroyed or removed
Browse files Browse the repository at this point in the history
In all physics servers, body_get_direct_state() now silently returns
nullptr when the body has been already freed or is removed from space,
so the client code can detect this state and invalidate the body rid.

In 2D, there is no change in behavior (just no more errors).

In 3D, the Bullet server returned a valid direct body state when the
body was removed from the physics space, but in this case it didn't
make sense to use the information from the body state.
  • Loading branch information
pouleyKetchoupp committed Nov 10, 2021
1 parent e8870dd commit bfd0d33
Show file tree
Hide file tree
Showing 7 changed files with 35 additions and 4 deletions.
2 changes: 1 addition & 1 deletion doc/classes/PhysicsServer2D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@
<return type="PhysicsDirectBodyState2D" />
<argument index="0" name="body" type="RID" />
<description>
Returns the [PhysicsDirectBodyState2D] of the body.
Returns the [PhysicsDirectBodyState2D] of the body. Returns [code]null[/code] if the body is destroyed or removed from the physics space.
</description>
</method>
<method name="body_get_max_contacts_reported" qualifiers="const">
Expand Down
2 changes: 1 addition & 1 deletion doc/classes/PhysicsServer3D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@
<return type="PhysicsDirectBodyState3D" />
<argument index="0" name="body" type="RID" />
<description>
Returns the [PhysicsDirectBodyState3D] of the body.
Returns the [PhysicsDirectBodyState3D] of the body. Returns [code]null[/code] if the body is destroyed or removed from the physics space.
</description>
</method>
<method name="body_get_max_contacts_reported" qualifiers="const">
Expand Down
9 changes: 9 additions & 0 deletions modules/bullet/bullet_physics_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -837,8 +837,17 @@ void BulletPhysicsServer3D::body_set_ray_pickable(RID p_body, bool p_enable) {
}

PhysicsDirectBodyState3D *BulletPhysicsServer3D::body_get_direct_state(RID p_body) {
if (!rigid_body_owner.owns(p_body)) {
return nullptr;
}

RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND_V(!body, nullptr);

if (!body->get_space()) {
return nullptr;
}

return BulletPhysicsDirectBodyState3D::get_singleton(body);
}

Expand Down
4 changes: 4 additions & 0 deletions scene/2d/physics_body_2d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1101,6 +1101,10 @@ bool CharacterBody2D::move_and_slide() {
if (bs) {
Vector2 local_position = gt.elements[2] - bs->get_transform().elements[2];
current_platform_velocity = bs->get_velocity_at_local_position(local_position);
} else {
// Body is removed or destroyed, invalidate floor.
current_platform_velocity = Vector2();
platform_rid = RID();
}
} else {
current_platform_velocity = Vector2();
Expand Down
4 changes: 4 additions & 0 deletions scene/3d/physics_body_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1145,6 +1145,10 @@ bool CharacterBody3D::move_and_slide() {
if (bs) {
Vector3 local_position = gt.origin - bs->get_transform().origin;
current_platform_velocity = bs->get_velocity_at_local_position(local_position);
} else {
// Body is removed or destroyed, invalidate floor.
current_platform_velocity = Vector3();
platform_rid = RID();
}
} else {
current_platform_velocity = Vector3();
Expand Down
9 changes: 8 additions & 1 deletion servers/physics_2d/godot_physics_server_2d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -963,10 +963,17 @@ bool GodotPhysicsServer2D::body_test_motion(RID p_body, const MotionParameters &
PhysicsDirectBodyState2D *GodotPhysicsServer2D::body_get_direct_state(RID p_body) {
ERR_FAIL_COND_V_MSG((using_threads && !doing_sync), nullptr, "Body state is inaccessible right now, wait for iteration or physics process notification.");

if (!body_owner.owns(p_body)) {
return nullptr;
}

GodotBody2D *body = body_owner.get_or_null(p_body);
ERR_FAIL_COND_V(!body, nullptr);

ERR_FAIL_COND_V(!body->get_space(), nullptr);
if (!body->get_space()) {
return nullptr;
}

ERR_FAIL_COND_V_MSG(body->get_space()->is_locked(), nullptr, "Body state is inaccessible right now, wait for iteration or physics process notification.");

return body->get_direct_state();
Expand Down
9 changes: 8 additions & 1 deletion servers/physics_3d/godot_physics_server_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -881,10 +881,17 @@ bool GodotPhysicsServer3D::body_test_motion(RID p_body, const MotionParameters &
PhysicsDirectBodyState3D *GodotPhysicsServer3D::body_get_direct_state(RID p_body) {
ERR_FAIL_COND_V_MSG((using_threads && !doing_sync), nullptr, "Body state is inaccessible right now, wait for iteration or physics process notification.");

if (!body_owner.owns(p_body)) {
return nullptr;
}

GodotBody3D *body = body_owner.get_or_null(p_body);
ERR_FAIL_NULL_V(body, nullptr);

ERR_FAIL_NULL_V(body->get_space(), nullptr);
if (!body->get_space()) {
return nullptr;
}

ERR_FAIL_COND_V_MSG(body->get_space()->is_locked(), nullptr, "Body state is inaccessible right now, wait for iteration or physics process notification.");

return body->get_direct_state();
Expand Down

0 comments on commit bfd0d33

Please sign in to comment.