extends SceneTree # One-off bake: runs ArenaBoundary's collider generation once and commits the # result into objects/arena_boundary.tscn, so every arena load (and every # parallel headless training env) skips regenerating ~170 CollisionShape3D # nodes at runtime — ArenaBoundary._ready() already skips this itself once a # bake matching the current goal_mode exists (see bake_colliders). # # Safe to re-run any time a geometry constant changes (arena size, corner/ # fillet radii, goal aperture, segment counts, etc.) — bake_colliders() clears # its own prior output first, so this replaces rather than duplicates: # godot --headless --path Game --script res://tools/bake_arena_boundary.gd const ARENA_BOUNDARY_PATH := "res://objects/arena_boundary.tscn" func _initialize() -> void: var packed: PackedScene = load(ARENA_BOUNDARY_PATH) var instance := packed.instantiate() instance.bake_colliders() # PackedScene.pack() only serializes nodes whose `owner` is set to the # scene root — newly created nodes have no owner by default, so without # this, pack() silently produces a scene with none of the just-built # colliders in it. _set_owner_recursive(instance, instance) var rebaked := PackedScene.new() var pack_result := rebaked.pack(instance) if pack_result != OK: push_error("bake_arena_boundary: pack() failed with error %d" % pack_result) quit(1) return var save_result := ResourceSaver.save(rebaked, ARENA_BOUNDARY_PATH) if save_result != OK: push_error("bake_arena_boundary: save() failed with error %d" % save_result) quit(1) return print("bake_arena_boundary: baked colliders into %s" % ARENA_BOUNDARY_PATH) quit() func _set_owner_recursive(node: Node, scene_root: Node) -> void: for child in node.get_children(): child.owner = scene_root _set_owner_recursive(child, scene_root)