extends SceneTree const PlayerView = preload("res://ui/player_view.gd") const Anchor = preload("res://fx/target_effect_anchor.gd") var failures := 0 func check(ok: bool, label: String) -> void: if not ok: failures += 1 printerr("FAIL: " + label) func _init() -> void: call_deferred("run") func run() -> void: var old_mode := OS.get_environment("MTGODOT_GPUSKIN") var centers := {} for mode in ["0", "1"]: OS.set_environment("MTGODOT_GPUSKIN", mode) for race in 8: var view := PlayerView.new() check(view.build(AssetRoot.path(), race), "race builds") root.add_child(view) view.anim.set_process(false) view.anim.set_time(0) var result: Dictionary = view.model.get_fly_target_bounds() check(result.valid, "source bone OBBs parsed race=%d mode=%s" % [race, mode]) var bounds: AABB = result.bounds check(bounds.size.is_finite() and bounds.size.length() > 50, "nonempty cm bounds") var center: Vector3 = Anchor.fly_target_position(view) check(center.distance_to(view.model.to_global(bounds.get_center())) < 0.00001, "source centre transforms once") if mode == "0": centers[race] = center else: check(center.distance_to(centers[race]) < 0.0001, "CPU/GPU target centres match") var extra := MeshInstance3D.new() extra.mesh = BoxMesh.new() extra.position = Vector3(1000, 1000, 1000) view.add_child(extra) view.set_anim_state("attack") view.anim.set_time(0.3) check(Anchor.fly_target_position(view).distance_to(center) < 0.00001, "cached body sphere excludes attachments and later poses") view.position = Vector3(5, 2, -3) check(Anchor.fly_target_position(view).distance_to(center + view.position) < 0.00001, "cached local sphere follows actor translation") view.free() OS.set_environment("MTGODOT_GPUSKIN", old_mode) await process_frame print("fly_target_bounds_test: failures=%d" % failures) quit(1 if failures else 0)