1
0
mirror of https://github.com/godotengine/godot.git synced 2025-12-06 17:25:19 +00:00

Fix multiple issues with 2D & 3D physics

- Use `NOTIFICATION_ENTER`/`EXIT_WORLD` for `Area` (intead of `*_TREE`).
- Now both bodies' and areas' constraints are cleaned up.
- And now also that happens as soon as the space is set to null (i.e., when exiting the tree) instead of only at freeing time.
- When clearing constraints, the loop goes on to the next if the current is already released, instead of breaking.
- When one has been already released, no error is shown from now on, as it's something expected, since a pair (our kind of constraint of interest) can be freed by any of its involved collision objects and the other will try again.
- Implement index shifting (or marking as -1) for shapes indices in collision pairs shapes are removed.
- Standarize behavior of bodies and areas so that anything that invalidates a given pair gives the same result (collision mask, actual collision, etc); for instance, triggering area enter/exit signals.
- Add missing member initializations.
- Extend the new-space-equals-area/body-current-space test to every case.
- Fix 3D ray-casts early accepting Areas (skipping the mask check).
- Fix unpairing of large elements (2D's `BroadPhase2DHashGrid`).

Some of these prevent random crashes caused by constraints with dangling pointers to involved objects.
Fixes #8856.
Fixes #7589.
Fixes #6676.
And maybe others.
This commit is contained in:
Pedro J. Estébanez
2017-05-30 18:56:43 +02:00
parent 5f98c16d59
commit 3e5e8b6c9e
27 changed files with 243 additions and 41 deletions

View File

@@ -222,13 +222,25 @@ void PhysicsServerSW::area_set_space(RID p_area, RID p_space) {
AreaSW *area = area_owner.get(p_area);
ERR_FAIL_COND(!area);
SpaceSW *space = NULL;
if (p_space.is_valid()) {
space = space_owner.get(p_space);
ERR_FAIL_COND(!space);
}
if (area->get_space() == space)
return; //pointless
area->set_space(space);
for (Set<ConstraintSW *>::Element *E = area->get_constraints().front(); E; E = E->next()) {
RID self = E->get()->get_self();
if (!self.is_valid())
continue;
free(self);
}
area->clear_constraints();
};
RID PhysicsServerSW::area_get_space(RID p_area) const {
@@ -463,6 +475,7 @@ void PhysicsServerSW::body_set_space(RID p_body, RID p_space) {
BodySW *body = body_owner.get(p_body);
ERR_FAIL_COND(!body);
SpaceSW *space = NULL;
if (p_space.is_valid()) {
@@ -471,9 +484,17 @@ void PhysicsServerSW::body_set_space(RID p_body, RID p_space) {
}
if (body->get_space() == space)
return; //pointles
return; //pointless
body->set_space(space);
for (Map<ConstraintSW *, int>::Element *E = body->get_constraint_map().front(); E; E = E->next()) {
RID self = E->key()->get_self();
if (!self.is_valid())
continue;
free(self);
}
body->clear_constraint_map();
};
RID PhysicsServerSW::body_get_space(RID p_body) const {
@@ -1302,19 +1323,13 @@ void PhysicsServerSW::free(RID p_rid) {
// if (body->get_direct_state_query())
// _clear_query(body->get_direct_state_query());
body->set_space(NULL);
body_set_space(p_rid, RID());
while (body->get_shape_count()) {
body->remove_shape(0);
}
while (body->get_constraint_map().size()) {
RID self = body->get_constraint_map().front()->key()->get_self();
ERR_FAIL_COND(!self.is_valid());
free(self);
}
body_owner.free(p_rid);
memdelete(body);
@@ -1325,7 +1340,7 @@ void PhysicsServerSW::free(RID p_rid) {
// if (area->get_monitor_query())
// _clear_query(area->get_monitor_query());
area->set_space(NULL);
area_set_space(p_rid, RID());
while (area->get_shape_count()) {