@tool extends MenuButton enum Operation {BAKE, COLLISION} enum Shape {TRIMESH, SINGLE_CONVEX, SIMPLE_CONVEX, MULTIPLE_CONVEX} enum Placement {SIBLING, CHILD} var path_mesh: Node var ur: EditorUndoRedoManager @onready var _err_dialog: AcceptDialog = $ErrDialog @onready var _collision_dialog: ConfirmationDialog = $CollisionDialog @onready var _shape_placement: OptionButton = $CollisionDialog/VBoxContainer/OptionButton @onready var _shape_type: OptionButton = $CollisionDialog/VBoxContainer/OptionButton2 @onready var _bake_dialog: ConfirmationDialog = $BakeDialog @onready var _bake_placement: OptionButton = $BakeDialog/VBoxContainer/OptionButton func _ready() -> void: get_popup().index_pressed.connect(_on_menu_pressed) _bake_dialog.confirmed.connect(_on_bake_confirmed) _collision_dialog.confirmed.connect(_on_collision_shape_confirmed) func _on_menu_pressed(id: int) -> void: match id: Operation.BAKE: _bake_dialog.popup_centered() Operation.COLLISION: _collision_dialog.popup_centered() func _on_bake_confirmed() -> void: if not (path_mesh is PathMesh3D or path_mesh is PathExtrude3D): return if not ur: return var placement := _bake_placement.selected var p_owner := EditorInterface.get_edited_scene_root() if p_owner == path_mesh and placement == Placement.SIBLING: _err_dialog.dialog_text = "Can't add Mesh Instance as sibling of scene root." _err_dialog.popup_centered() return var mesh: Mesh = path_mesh.get_baked_mesh() if mesh == null: _err_dialog.dialog_text = "No mesh to create Instance from." _err_dialog.popup_centered() return var minstance := MeshInstance3D.new() minstance.mesh = mesh minstance.name = "MeshInstance3D" if placement == Placement.SIBLING: ur.add_do_method(path_mesh, "add_sibling", minstance, true) ur.add_do_method(minstance, "set_owner", p_owner) ur.add_do_reference(minstance) ur.add_undo_method(path_mesh.get_parent(), "remove_child", minstance) else: ur.add_do_method(path_mesh, "add_child", minstance, true) ur.add_do_method(minstance, "set_owner", p_owner) ur.add_do_reference(minstance) ur.add_undo_method(path_mesh, "remove_child", minstance) ur.commit_action() func _on_collision_shape_confirmed() -> void: if not (path_mesh is PathMesh3D or path_mesh is PathExtrude3D): return if not ur: return var mesh: Mesh = path_mesh.get_baked_mesh() if mesh == null: _err_dialog.dialog_text = "No mesh to create Collision Shape from." _err_dialog.popup_centered() return var placement := _shape_placement.selected var shape_type := _shape_type.selected var str := "Collision Shape Sibling" if placement == Placement.SIBLING else "Static Body" match shape_type: Shape.TRIMESH: ur.create_action("Create Trimesh " + str) Shape.SINGLE_CONVEX: ur.create_action("Create Single Convex " + str) Shape.SIMPLE_CONVEX: ur.create_action("Create Simplified Convex "+ str) Shape.MULTIPLE_CONVEX: ur.create_action("Create Multiple Convex " + str) _: return if EditorInterface.get_edited_scene_root() == path_mesh and placement == 0: _err_dialog.dialog_text = "Can't create a collision shape as sibling for the scene root." _err_dialog.popup_centered() return var scene_owner := EditorInterface.get_edited_scene_root() var shapes: Array[Shape3D] = [] match shape_type: Shape.TRIMESH: shapes.push_back(mesh.create_trimesh_shape()) Shape.SINGLE_CONVEX: shapes.push_back(mesh.create_convex_shape(true, false)) Shape.SIMPLE_CONVEX: shapes.push_back(mesh.create_convex_shape(true, true)) Shape.MULTIPLE_CONVEX: var settings := MeshConvexDecompositionSettings.new() settings.max_convex_hulls = 32 settings.max_concavity = 0.001 shapes = mesh.convex_decompose(settings) if shapes.is_empty(): _err_dialog.dialog_text = "Cannot create collision shape." _err_dialog.popup_centered() return var p_owner := EditorInterface.get_edited_scene_root() if placement == Placement.CHILD: var body := StaticBody3D.new() ur.add_do_method(path_mesh, "add_child", body, true) ur.add_do_method(body, "set_owner", p_owner) for shape: Shape3D in shapes: var cshape := CollisionShape3D.new() cshape.shape = shape ur.add_do_method(body, "add_child", cshape, true) ur.add_do_method(cshape, "set_owner", p_owner) ur.add_do_reference(body) ur.add_undo_method(path_mesh, "remove_child", body) else: for shape: Shape3D in shapes: var cshape := CollisionShape3D.new() cshape.shape = shape cshape.name = "CollisionShape3D" cshape.transform = path_mesh.transform ur.add_do_method(path_mesh, "add_sibling", cshape, true) ur.add_do_method(cshape, "set_owner", p_owner) ur.add_do_reference(cshape) ur.add_undo_method(path_mesh.get_parent(), "remove_child", cshape) ur.commit_action()