Gate library prop collision coverage across venues
This commit is contained in:
1 parent
fe3ba3054e
commit
5dec59355a
4 files changed
+84
-1
No files matched your search
@@ -296,3 +296,61 @@ func test_door_indicator_built() -> bool:
|
||||
return a and b and c
|
||||
root.free()
|
||||
return a
|
||||
|
||||
## 3D review gate: a placed prop that people can walk into must publish both a
|
||||
## static body and a navigation-avoidance footprint. A prop whose bounds are
|
||||
## empty (broken GLB/fallback) used to lose its collider silently.
|
||||
func test_every_placed_prop_has_a_collider_and_avoidance() -> bool:
|
||||
var problems: Array[String] = []
|
||||
for venue in ["hollywood_building", "joke_shop", "tv_studio"]:
|
||||
var root := Node3D.new()
|
||||
var builder := WorldBuilder.new(root, venue)
|
||||
builder.build()
|
||||
var holders := root.find_children("Prop_*", "Node3D", true, false)
|
||||
if holders.size() < 8:
|
||||
problems.append("%s places only %d props" % [venue, holders.size()])
|
||||
for holder in holders:
|
||||
var body := holder.get_node_or_null("Collision") as StaticBody3D
|
||||
var shape := body.get_node_or_null("Shape") as CollisionShape3D if body != null else null
|
||||
var obstacle := holder.get_node_or_null("Avoidance") as NavigationObstacle3D
|
||||
if body == null or shape == null or shape.shape == null:
|
||||
problems.append("%s/%s has no collision shape" % [venue, holder.name])
|
||||
if obstacle == null or obstacle.radius <= 0.0:
|
||||
problems.append("%s/%s has no avoidance radius" % [venue, holder.name])
|
||||
root.free()
|
||||
return TestUtils.check(problems.is_empty(),
|
||||
"placed props are covered: %s" % ", ".join(problems.slice(0, 6)))
|
||||
|
||||
## Library dressing must either publish a walk-blocking body or be on the
|
||||
## documented mounted/decorative list. The check also proves the metadata that
|
||||
## ties a node to its catalogue asset is present.
|
||||
func test_library_dressing_collision_matches_the_documented_exemptions() -> bool:
|
||||
var problems: Array[String] = []
|
||||
for venue in ["hollywood_building", "joke_shop", "tv_studio"]:
|
||||
var root := Node3D.new()
|
||||
var builder := WorldBuilder.new(root, venue)
|
||||
builder.build()
|
||||
if builder.library_nodes.is_empty():
|
||||
problems.append("%s placed no library dressing" % venue)
|
||||
for node in builder.library_nodes:
|
||||
if not is_instance_valid(node):
|
||||
continue
|
||||
var prop := str(node.get_meta("library_prop", ""))
|
||||
if prop == "":
|
||||
problems.append("%s/%s has no library_prop metadata" % [venue, node.name])
|
||||
continue
|
||||
if WorldBuilder.NON_BLOCKING_LIBRARY.has(prop):
|
||||
continue
|
||||
if _walk_blocking_body(node) == null:
|
||||
problems.append("%s/%s (%s) blocks walking without a body" % [venue, node.name, prop])
|
||||
root.free()
|
||||
return TestUtils.check(problems.is_empty(),
|
||||
"library dressing is covered: %s" % ", ".join(problems.slice(0, 6)))
|
||||
|
||||
func _walk_blocking_body(node: Node) -> StaticBody3D:
|
||||
for child in node.find_children("*", "StaticBody3D", true, false):
|
||||
var body := child as StaticBody3D
|
||||
for shape in body.find_children("*", "CollisionShape3D", true, false):
|
||||
if (shape as CollisionShape3D).shape != null:
|
||||
return body
|
||||
return null
|
||||
Reference in new issue
Block a user