diff --git a/fast64_internal/mk64/mk64_operators.py b/fast64_internal/mk64/mk64_operators.py index fb1d60098..edfde12ea 100644 --- a/fast64_internal/mk64/mk64_operators.py +++ b/fast64_internal/mk64/mk64_operators.py @@ -103,66 +103,106 @@ def execute(self, context): class MK64_ExportCourse(Operator): bl_idname = "scene.mk64_export_course" - bl_label = "Export Course" + bl_label = "Export Track" def execute(self, context): mk64_props: MK64_Properties = context.scene.fast64.mk64 - if context.mode != "OBJECT": - bpy.ops.object.mode_set(mode="OBJECT") + + prev_mode = context.mode + prev_active = context.view_layer.objects.active + root = None + rotation_applied = False + try: - all_objs = context.selected_objects - if len(all_objs) == 0: + # ----------------------------- + # Ensure object mode + # ----------------------------- + if context.object and context.mode != "OBJECT": + bpy.ops.object.mode_set(mode="OBJECT") + + # ----------------------------- + # Root resolution (can error) + # ----------------------------- + selected = context.selected_objects + if not selected: raise PluginError("No objects selected.") - obj = context.selected_objects[0] - root = obj - if not root.fast64.mk64.obj_type == "Course Root": - while root.parent: - root = root.parent - if root.fast64.mk64.obj_type == "Course Root": - break - assert root.fast64.mk64.obj_type == "Course Root", PluginError("Object must be a course root") - - scale = mk64_props.scale - final_transform = mathutils.Matrix.Diagonal(mathutils.Vector((scale, scale, scale))).to_4x4() - except Exception as e: - if context.mode != "OBJECT": - bpy.ops.object.mode_set(mode="OBJECT") - raisePluginError(self, e) - return {"CANCELLED"} # must return a set + selected_roots = [ + obj for obj in selected + if obj.type == "EMPTY" + and obj.fast64.mk64.obj_type == "Course Root" + ] - finalTransform = 1 + if len(selected_roots) > 1: + raise PluginError("Multiple Course Roots selected.") - try: + if selected_roots: + root = selected_roots[0] + else: + course_roots = set() + for obj in selected: + current = obj + visited = set() + while current and current not in visited: + visited.add(current) + if ( + current.type == "EMPTY" + and current.fast64.mk64.obj_type == "Course Root" + ): + course_roots.add(current) + break + current = current.parent + + if not course_roots: + raise PluginError("No Course Root found.") + + if len(course_roots) > 1: + raise PluginError( + "Multiple Course Roots found. Select one explicitly." + ) + + root = course_roots.pop() + + # ----------------------------- + # Export work + # ----------------------------- applyRotation([root], math.radians(90), "X") + rotation_applied = True name = mk64_props.course_export_settings.name - export_path = Path(bpy.path.abspath(mk64_props.course_export_settings.export_path)) -# internal_path = os.path.join(mk64_props.course_export_settings.internal_game_path, name).replace("\\", "/") - internal_path = Path(os.path.join("tracks", name).replace("\\", "/")) - (full_path := export_path / internal_path).mkdir(parents=True, exist_ok=True) - internal_path = internal_path.as_posix() + export_path = Path(bpy.path.abspath( + mk64_props.course_export_settings.export_path + )) - - saveTextures = context.scene.saveTextures - exportSettings = context.scene.fast64.oot.DLExportSettings + internal_path = Path("tracks") / name + (export_path / internal_path).mkdir(parents=True, exist_ok=True) if context.scene.fast64.mk64.featureSet == "HM64": - export_course_xml(obj, context, export_path, internal_path, self.report) + export_course_xml(root, context, export_path, internal_path.as_posix(), self.report) else: export_course_c(root, context, export_path) self.report({"INFO"}, "Success!") - applyRotation([root], math.radians(-90), "X") - return {"FINISHED"} # must return a set + return {"FINISHED"} except Exception as e: - if context.mode != "OBJECT": - bpy.ops.object.mode_set(mode="OBJECT") - applyRotation([root], math.radians(-90), "X") - raisePluginError(self, e) - return {"CANCELLED"} # must return a set + return {"CANCELLED"} + + finally: + # ----------------------------- + # Guaranteed cleanup + # ----------------------------- + if rotation_applied and root: + applyRotation([root], math.radians(-90), "X") + + if context.object and context.mode != prev_mode: + context.view_layer.objects.active = prev_active + if prev_mode.startswith("EDIT") and context.object.type in {"MESH", "CURVE", "ARMATURE"}: + bpy.ops.object.mode_set(mode="EDIT") + elif prev_mode in {"OBJECT", "POSE", "SCULPT"}: + bpy.ops.object.mode_set(mode=prev_mode) + mk64_operator_classes = (MK64_ImportCourseDL, MK64_ExportCourse) diff --git a/fast64_internal/mk64/mk64_panels.py b/fast64_internal/mk64/mk64_panels.py index 473471354..27745723f 100644 --- a/fast64_internal/mk64/mk64_panels.py +++ b/fast64_internal/mk64/mk64_panels.py @@ -34,7 +34,6 @@ def draw(self, context): class MK64_ExportCoursePanel(MK64_Panel): bl_label = "SpaghettiKart Track Export" bl_idname = "MK64_PT_export_course" - bl_context = "objectmode" def draw(self, context): col = self.layout.column()