Explorar el Código

Prevent mapping areas with invalid IDs for `Area2D/3D`

This occurs when areas are created directly from the servers, and no
instance is linked.
A Thousand Ships hace 2 años
padre
commit
0081a50e32
Se han modificado 4 ficheros con 64 adiciones y 2 borrados
  1. 1 0
      doc/classes/Area2D.xml
  2. 1 0
      doc/classes/Area3D.xml
  3. 30 0
      scene/2d/area_2d.cpp
  4. 32 2
      scene/3d/area_3d.cpp

+ 1 - 0
doc/classes/Area2D.xml

@@ -6,6 +6,7 @@
 	<description>
 	<description>
 		[Area2D] is a region of 2D space defined by one or multiple [CollisionShape2D] or [CollisionPolygon2D] child nodes. It detects when other [CollisionObject2D]s enter or exit it, and it also keeps track of which collision objects haven't exited it yet (i.e. which one are overlapping it).
 		[Area2D] is a region of 2D space defined by one or multiple [CollisionShape2D] or [CollisionPolygon2D] child nodes. It detects when other [CollisionObject2D]s enter or exit it, and it also keeps track of which collision objects haven't exited it yet (i.e. which one are overlapping it).
 		This node can also locally alter or override physics parameters (gravity, damping) and route audio to custom audio buses.
 		This node can also locally alter or override physics parameters (gravity, damping) and route audio to custom audio buses.
+		[b]Note:[/b] Areas and bodies created with [PhysicsServer2D] might not interact as expected with [Area2D]s, and might not emit signals or track objects correctly.
 	</description>
 	</description>
 	<tutorials>
 	<tutorials>
 		<link title="Using Area2D">$DOCS_URL/tutorials/physics/using_area_2d.html</link>
 		<link title="Using Area2D">$DOCS_URL/tutorials/physics/using_area_2d.html</link>

+ 1 - 0
doc/classes/Area3D.xml

@@ -6,6 +6,7 @@
 	<description>
 	<description>
 		[Area3D] is a region of 3D space defined by one or multiple [CollisionShape3D] or [CollisionPolygon3D] child nodes. It detects when other [CollisionObject3D]s enter or exit it, and it also keeps track of which collision objects haven't exited it yet (i.e. which one are overlapping it).
 		[Area3D] is a region of 3D space defined by one or multiple [CollisionShape3D] or [CollisionPolygon3D] child nodes. It detects when other [CollisionObject3D]s enter or exit it, and it also keeps track of which collision objects haven't exited it yet (i.e. which one are overlapping it).
 		This node can also locally alter or override physics parameters (gravity, damping) and route audio to custom audio buses.
 		This node can also locally alter or override physics parameters (gravity, damping) and route audio to custom audio buses.
+		[b]Note:[/b] Areas and bodies created with [PhysicsServer3D] might not interact as expected with [Area3D]s, and might not emit signals or track objects correctly.
 		[b]Warning:[/b] Using a [ConcavePolygonShape3D] inside a [CollisionShape3D] child of this node (created e.g. by using the [b]Create Trimesh Collision Sibling[/b] option in the [b]Mesh[/b] menu that appears when selecting a [MeshInstance3D] node) may give unexpected results, since this collision shape is hollow. If this is not desired, it has to be split into multiple [ConvexPolygonShape3D]s or primitive shapes like [BoxShape3D], or in some cases it may be replaceable by a [CollisionPolygon3D].
 		[b]Warning:[/b] Using a [ConcavePolygonShape3D] inside a [CollisionShape3D] child of this node (created e.g. by using the [b]Create Trimesh Collision Sibling[/b] option in the [b]Mesh[/b] menu that appears when selecting a [MeshInstance3D] node) may give unexpected results, since this collision shape is hollow. If this is not desired, it has to be split into multiple [ConvexPolygonShape3D]s or primitive shapes like [BoxShape3D], or in some cases it may be replaceable by a [CollisionPolygon3D].
 	</description>
 	</description>
 	<tutorials>
 	<tutorials>

+ 30 - 0
scene/2d/area_2d.cpp

@@ -166,6 +166,21 @@ void Area2D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, i
 	bool body_in = p_status == PhysicsServer2D::AREA_BODY_ADDED;
 	bool body_in = p_status == PhysicsServer2D::AREA_BODY_ADDED;
 	ObjectID objid = p_instance;
 	ObjectID objid = p_instance;
 
 
+	// Exit early if instance is invalid.
+	if (objid.is_null()) {
+		// Emit the appropriate signals.
+		lock_callback();
+		locked = true;
+		if (body_in) {
+			emit_signal(SceneStringNames::get_singleton()->body_shape_entered, p_body, (Node *)nullptr, p_body_shape, p_area_shape);
+		} else {
+			emit_signal(SceneStringNames::get_singleton()->body_shape_exited, p_body, (Node *)nullptr, p_body_shape, p_area_shape);
+		}
+		locked = false;
+		unlock_callback();
+		return;
+	}
+
 	Object *obj = ObjectDB::get_instance(objid);
 	Object *obj = ObjectDB::get_instance(objid);
 	Node *node = Object::cast_to<Node>(obj);
 	Node *node = Object::cast_to<Node>(obj);
 
 
@@ -262,6 +277,21 @@ void Area2D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, i
 	bool area_in = p_status == PhysicsServer2D::AREA_BODY_ADDED;
 	bool area_in = p_status == PhysicsServer2D::AREA_BODY_ADDED;
 	ObjectID objid = p_instance;
 	ObjectID objid = p_instance;
 
 
+	// Exit early if instance is invalid.
+	if (objid.is_null()) {
+		// Emit the appropriate signals.
+		lock_callback();
+		locked = true;
+		if (area_in) {
+			emit_signal(SceneStringNames::get_singleton()->area_shape_entered, p_area, (Node *)nullptr, p_area_shape, p_self_shape);
+		} else {
+			emit_signal(SceneStringNames::get_singleton()->area_shape_exited, p_area, (Node *)nullptr, p_area_shape, p_self_shape);
+		}
+		locked = false;
+		unlock_callback();
+		return;
+	}
+
 	Object *obj = ObjectDB::get_instance(objid);
 	Object *obj = ObjectDB::get_instance(objid);
 	Node *node = Object::cast_to<Node>(obj);
 	Node *node = Object::cast_to<Node>(obj);
 
 

+ 32 - 2
scene/3d/area_3d.cpp

@@ -223,6 +223,21 @@ void Area3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, i
 	bool body_in = p_status == PhysicsServer3D::AREA_BODY_ADDED;
 	bool body_in = p_status == PhysicsServer3D::AREA_BODY_ADDED;
 	ObjectID objid = p_instance;
 	ObjectID objid = p_instance;
 
 
+	// Exit early if instance is invalid.
+	if (objid.is_null()) {
+		lock_callback();
+		locked = true;
+		// Emit the appropriate signals.
+		if (body_in) {
+			emit_signal(SceneStringNames::get_singleton()->body_shape_entered, p_body, (Node *)nullptr, p_body_shape, p_area_shape);
+		} else {
+			emit_signal(SceneStringNames::get_singleton()->body_shape_exited, p_body, (Node *)nullptr, p_body_shape, p_area_shape);
+		}
+		locked = false;
+		unlock_callback();
+		return;
+	}
+
 	Object *obj = ObjectDB::get_instance(objid);
 	Object *obj = ObjectDB::get_instance(objid);
 	Node *node = Object::cast_to<Node>(obj);
 	Node *node = Object::cast_to<Node>(obj);
 
 
@@ -254,7 +269,7 @@ void Area3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, i
 			E->value.shapes.insert(ShapePair(p_body_shape, p_area_shape));
 			E->value.shapes.insert(ShapePair(p_body_shape, p_area_shape));
 		}
 		}
 
 
-		if (E->value.in_tree) {
+		if (!node || E->value.in_tree) {
 			emit_signal(SceneStringNames::get_singleton()->body_shape_entered, p_body, node, p_body_shape, p_area_shape);
 			emit_signal(SceneStringNames::get_singleton()->body_shape_entered, p_body, node, p_body_shape, p_area_shape);
 		}
 		}
 
 
@@ -276,7 +291,7 @@ void Area3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, i
 				}
 				}
 			}
 			}
 		}
 		}
-		if (node && in_tree) {
+		if (!node || in_tree) {
 			emit_signal(SceneStringNames::get_singleton()->body_shape_exited, p_body, obj, p_body_shape, p_area_shape);
 			emit_signal(SceneStringNames::get_singleton()->body_shape_exited, p_body, obj, p_body_shape, p_area_shape);
 		}
 		}
 	}
 	}
@@ -414,6 +429,21 @@ void Area3D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, i
 	bool area_in = p_status == PhysicsServer3D::AREA_BODY_ADDED;
 	bool area_in = p_status == PhysicsServer3D::AREA_BODY_ADDED;
 	ObjectID objid = p_instance;
 	ObjectID objid = p_instance;
 
 
+	// Exit if instance is invalid.
+	if (objid.is_null()) {
+		lock_callback();
+		locked = true;
+		// Emit the appropriate signals.
+		if (area_in) {
+			emit_signal(SceneStringNames::get_singleton()->area_shape_entered, p_area, (Node *)nullptr, p_area_shape, p_self_shape);
+		} else {
+			emit_signal(SceneStringNames::get_singleton()->area_shape_exited, p_area, (Node *)nullptr, p_area_shape, p_self_shape);
+		}
+		locked = false;
+		unlock_callback();
+		return;
+	}
+
 	Object *obj = ObjectDB::get_instance(objid);
 	Object *obj = ObjectDB::get_instance(objid);
 	Node *node = Object::cast_to<Node>(obj);
 	Node *node = Object::cast_to<Node>(obj);