From 81cdaaa60f49fe734766fdbf304f059423ea5676 Mon Sep 17 00:00:00 2001 From: Yanis002 <35189056+Yanis002@users.noreply.github.com> Date: Sun, 30 Nov 2025 15:23:18 +0100 Subject: [PATCH] fixed local view issue --- fast64_internal/utility.py | 28 +++ .../z64/animated_mats/operators.py | 17 +- fast64_internal/z64/animation/operators.py | 43 ++--- fast64_internal/z64/collision/operators.py | 41 ++--- fast64_internal/z64/cutscene/operators.py | 92 +++++----- fast64_internal/z64/f3d/operators.py | 69 ++++---- fast64_internal/z64/scene/operators.py | 163 +++++++++--------- fast64_internal/z64/skeleton/operators.py | 77 +++++---- 8 files changed, 284 insertions(+), 246 deletions(-) diff --git a/fast64_internal/utility.py b/fast64_internal/utility.py index c4d4d2ab0..37f057dd3 100644 --- a/fast64_internal/utility.py +++ b/fast64_internal/utility.py @@ -2138,3 +2138,31 @@ def get_new_empty_object( ): """Creates and returns a new empty object""" return get_new_object(name, None, do_select, location, rotation_euler, scale, parent) + + +class ExportUtils: + def __init__(self): + # get areas that are currently in local view mode + self.areas = [] + for area in bpy.context.screen.areas: + if area.type == "VIEW_3D" and area.spaces.active.local_view is not None: + self.areas.append(area) + + def __enter__(self): + # disable local views if enabled + for area in self.areas: + with bpy.context.temp_override(area=area): + bpy.ops.view3d.localview() + + return self + + def __exit__(self, exc_type, exc_value, traceback): + # restore local views + for area in self.areas: + with bpy.context.temp_override(area=area): + bpy.ops.view3d.localview() + + if exc_value: + print("\nExecution type:", exc_type) + print("\nExecution value:", exc_value) + print("\nTraceback:", traceback) diff --git a/fast64_internal/z64/animated_mats/operators.py b/fast64_internal/z64/animated_mats/operators.py index 45e8b3ba8..aec62be3e 100644 --- a/fast64_internal/z64/animated_mats/operators.py +++ b/fast64_internal/z64/animated_mats/operators.py @@ -1,7 +1,7 @@ from bpy.utils import register_class, unregister_class from bpy.types import Operator -from ...utility import raisePluginError +from ...utility import ExportUtils, raisePluginError class Z64_ExportAnimatedMaterials(Operator): @@ -12,13 +12,14 @@ class Z64_ExportAnimatedMaterials(Operator): def execute(self, context): from ..exporter.scene.animated_mats import SceneAnimatedMaterial - try: - SceneAnimatedMaterial.export() - self.report({"INFO"}, "Success!") - return {"FINISHED"} - except Exception as e: - raisePluginError(self, e) - return {"CANCELLED"} + with ExportUtils() as export_utils: + try: + SceneAnimatedMaterial.export() + self.report({"INFO"}, "Success!") + return {"FINISHED"} + except Exception as e: + raisePluginError(self, e) + return {"CANCELLED"} class Z64_ImportAnimatedMaterials(Operator): diff --git a/fast64_internal/z64/animation/operators.py b/fast64_internal/z64/animation/operators.py index 4c830812c..1d4ecd534 100644 --- a/fast64_internal/z64/animation/operators.py +++ b/fast64_internal/z64/animation/operators.py @@ -3,7 +3,7 @@ from bpy.props import StringProperty, BoolProperty from bpy.utils import register_class, unregister_class from bpy.ops import object -from ...utility import PluginError, toAlnum, writeCData, raisePluginError +from ...utility import PluginError, ExportUtils, toAlnum, writeCData, raisePluginError from .properties import OOTAnimExportSettingsProperty, OOTAnimImportSettingsProperty from ..exporter.animation import ootExportLinkAnimation, ootExportNonLinkAnimation from .importer import ootImportLinkAnimationC, ootImportNonLinkAnimationC @@ -123,26 +123,27 @@ class OOT_ExportAnim(Operator): # Called on demand (i.e. button press, menu item) # Can also be called from operator search menu (Spacebar) def execute(self, context): - try: - if len(context.selected_objects) == 0 or not isinstance(context.selected_objects[0].data, Armature): - raise PluginError("Armature not selected.") - if len(context.selected_objects) > 1: - raise PluginError("Multiple objects selected, make sure to select only one.") - armatureObj = context.selected_objects[0] - if context.mode != "OBJECT": - object.mode_set(mode="OBJECT") - except Exception as e: - raisePluginError(self, e) - return {"CANCELLED"} - - try: - settings = context.scene.fast64.oot.animExportSettings - exportAnimationC(armatureObj, settings) - self.report({"INFO"}, "Success!") - - except Exception as e: - raisePluginError(self, e) - return {"CANCELLED"} # must return a set + with ExportUtils() as export_utils: + try: + if len(context.selected_objects) == 0 or not isinstance(context.selected_objects[0].data, Armature): + raise PluginError("Armature not selected.") + if len(context.selected_objects) > 1: + raise PluginError("Multiple objects selected, make sure to select only one.") + armatureObj = context.selected_objects[0] + if context.mode != "OBJECT": + object.mode_set(mode="OBJECT") + except Exception as e: + raisePluginError(self, e) + return {"CANCELLED"} + + try: + settings = context.scene.fast64.oot.animExportSettings + exportAnimationC(armatureObj, settings) + self.report({"INFO"}, "Success!") + + except Exception as e: + raisePluginError(self, e) + return {"CANCELLED"} # must return a set return {"FINISHED"} # must return a set diff --git a/fast64_internal/z64/collision/operators.py b/fast64_internal/z64/collision/operators.py index ee7b87bb3..48321d093 100644 --- a/fast64_internal/z64/collision/operators.py +++ b/fast64_internal/z64/collision/operators.py @@ -3,7 +3,7 @@ from bpy.ops import object from mathutils import Matrix -from ...utility import PluginError, raisePluginError +from ...utility import PluginError, ExportUtils, raisePluginError from ..utility import getOOTScale from ..exporter.collision import CollisionHeader from .properties import OOTCollisionExportSettings @@ -16,27 +16,28 @@ class OOT_ExportCollision(Operator): bl_options = {"REGISTER", "UNDO", "PRESET"} def execute(self, context): - obj = None - if context.mode != "OBJECT": - object.mode_set(mode="OBJECT") - if len(context.selected_objects) == 0: - raise PluginError("No object selected.") - obj = context.active_object - if obj.type != "MESH": - raise PluginError("No mesh object selected.") - - try: - transform = Matrix.Scale(getOOTScale(obj.ootActorScale), 4) - settings: OOTCollisionExportSettings = context.scene.fast64.oot.collisionExportSettings - CollisionHeader.export(obj, transform, settings) - - self.report({"INFO"}, "Success!") - return {"FINISHED"} - except Exception as e: + with ExportUtils() as export_utils: + obj = None if context.mode != "OBJECT": object.mode_set(mode="OBJECT") - raisePluginError(self, e) - return {"CANCELLED"} # must return a set + if len(context.selected_objects) == 0: + raise PluginError("No object selected.") + obj = context.active_object + if obj.type != "MESH": + raise PluginError("No mesh object selected.") + + try: + transform = Matrix.Scale(getOOTScale(obj.ootActorScale), 4) + settings: OOTCollisionExportSettings = context.scene.fast64.oot.collisionExportSettings + CollisionHeader.export(obj, transform, settings) + + self.report({"INFO"}, "Success!") + return {"FINISHED"} + except Exception as e: + if context.mode != "OBJECT": + object.mode_set(mode="OBJECT") + raisePluginError(self, e) + return {"CANCELLED"} # must return a set oot_col_classes = (OOT_ExportCollision,) diff --git a/fast64_internal/z64/cutscene/operators.py b/fast64_internal/z64/cutscene/operators.py index 1cca8a2b6..040651ef3 100644 --- a/fast64_internal/z64/cutscene/operators.py +++ b/fast64_internal/z64/cutscene/operators.py @@ -5,7 +5,7 @@ from bpy.props import StringProperty, EnumProperty, IntProperty from bpy.types import Scene, Operator, Object from bpy.utils import register_class, unregister_class -from ...utility import PluginError, raisePluginError +from ...utility import PluginError, ExportUtils, raisePluginError from ...game_data import game_data from ..collection_utility import getCollection from .constants import ootEnumCSTextboxType @@ -73,28 +73,29 @@ class OOT_ExportCutscene(Operator): bl_options = {"REGISTER", "UNDO", "PRESET"} def execute(self, context): - try: - if context.mode != "OBJECT": - object.mode_set(mode="OBJECT") + with ExportUtils() as export_utils: + try: + if context.mode != "OBJECT": + object.mode_set(mode="OBJECT") - if context.scene.fast64.oot.export_cutscene_obj is not None: - cs_obj = context.scene.fast64.oot.export_cutscene_obj - else: - cs_obj = context.view_layer.objects.active + if context.scene.fast64.oot.export_cutscene_obj is not None: + cs_obj = context.scene.fast64.oot.export_cutscene_obj + else: + cs_obj = context.view_layer.objects.active - if cs_obj is None or cs_obj.type != "EMPTY" or cs_obj.ootEmptyType != "Cutscene": - raise PluginError("You must select a cutscene object") + if cs_obj is None or cs_obj.type != "EMPTY" or cs_obj.ootEmptyType != "Cutscene": + raise PluginError("You must select a cutscene object") - if cs_obj.parent is not None: - raise PluginError("Cutscene object must not be parented to anything") + if cs_obj.parent is not None: + raise PluginError("Cutscene object must not be parented to anything") - Cutscene.export(cs_obj) + Cutscene.export(cs_obj) - self.report({"INFO"}, "Successfully exported cutscene") - return {"FINISHED"} - except Exception as e: - raisePluginError(self, e) - return {"CANCELLED"} + self.report({"INFO"}, "Successfully exported cutscene") + return {"FINISHED"} + except Exception as e: + raisePluginError(self, e) + return {"CANCELLED"} class OOT_ExportAllCutscenes(Operator): @@ -103,33 +104,34 @@ class OOT_ExportAllCutscenes(Operator): bl_options = {"REGISTER", "UNDO", "PRESET"} def execute(self, context): - try: - if context.mode != "OBJECT": - object.mode_set(mode="OBJECT") - - cs_obj_list: list[Object] = [] - - for obj in context.view_layer.objects: - if obj.type == "EMPTY" and obj.ootEmptyType == "Cutscene": - if obj.parent is not None: - print(f"Parent: {obj.parent.name}, Object: {obj.name}") - raise PluginError("Cutscene object must not be parented to anything") - - cs_obj_list.append(obj) - - for count, cs_obj in enumerate(cs_obj_list, 1): - # skip the includes if this isn't the first cutscene - # skip the #endif directive if this isn't the last cutscene - Cutscene.export(cs_obj, count > 1, count < len(cs_obj_list)) - - if count == 0: - raise PluginError("Could not find any cutscenes to export") - - self.report({"INFO"}, "Successfully exported " + str(count) + " cutscenes") - return {"FINISHED"} - except Exception as e: - raisePluginError(self, e) - return {"CANCELLED"} + with ExportUtils() as export_utils: + try: + if context.mode != "OBJECT": + object.mode_set(mode="OBJECT") + + cs_obj_list: list[Object] = [] + + for obj in context.view_layer.objects: + if obj.type == "EMPTY" and obj.ootEmptyType == "Cutscene": + if obj.parent is not None: + print(f"Parent: {obj.parent.name}, Object: {obj.name}") + raise PluginError("Cutscene object must not be parented to anything") + + cs_obj_list.append(obj) + + for count, cs_obj in enumerate(cs_obj_list, 1): + # skip the includes if this isn't the first cutscene + # skip the #endif directive if this isn't the last cutscene + Cutscene.export(cs_obj, count > 1, count < len(cs_obj_list)) + + if count == 0: + raise PluginError("Could not find any cutscenes to export") + + self.report({"INFO"}, "Successfully exported " + str(count) + " cutscenes") + return {"FINISHED"} + except Exception as e: + raisePluginError(self, e) + return {"CANCELLED"} class OOT_SearchCSDestinationEnumOperator(Operator): diff --git a/fast64_internal/z64/f3d/operators.py b/fast64_internal/z64/f3d/operators.py index 82393ba9c..891e10190 100644 --- a/fast64_internal/z64/f3d/operators.py +++ b/fast64_internal/z64/f3d/operators.py @@ -9,7 +9,7 @@ from mathutils import Matrix from typing import Optional -from ...utility import CData, PluginError, raisePluginError, writeCData, toAlnum +from ...utility import CData, PluginError, ExportUtils, raisePluginError, writeCData, toAlnum from ...f3d.f3d_parser import importMeshC, getImportData from ...f3d.f3d_gbi import DLFormat, TextureExportSettings, ScrollMethod, get_F3D_GBI from ...f3d.f3d_writer import TriangleConverterInfo, removeDL, saveStaticModel, getInfoDict @@ -188,41 +188,42 @@ class OOT_ExportDL(Operator): # Called on demand (i.e. button press, menu item) # Can also be called from operator search menu (Spacebar) def execute(self, context): - obj = None - if context.mode != "OBJECT": - object.mode_set(mode="OBJECT") - if len(context.selected_objects) == 0: - raise PluginError("Mesh not selected.") - obj = context.active_object - if obj.type != "MESH": - raise PluginError("Mesh not selected.") - - finalTransform = Matrix.Scale(getOOTScale(obj.ootActorScale), 4) - - try: - # exportPath, levelName = getPathAndLevel(context.scene.geoCustomExport, - # context.scene.geoExportPath, context.scene.geoLevelName, - # context.scene.geoLevelOption) - - saveTextures = context.scene.saveTextures - exportSettings = context.scene.fast64.oot.DLExportSettings - - ootConvertMeshToC( - obj, - finalTransform, - DLFormat.Static, - saveTextures, - exportSettings, - ) - - self.report({"INFO"}, "Success!") - return {"FINISHED"} - - except Exception as e: + with ExportUtils() as export_utils: + obj = None if context.mode != "OBJECT": object.mode_set(mode="OBJECT") - raisePluginError(self, e) - return {"CANCELLED"} # must return a set + if len(context.selected_objects) == 0: + raise PluginError("Mesh not selected.") + obj = context.active_object + if obj.type != "MESH": + raise PluginError("Mesh not selected.") + + finalTransform = Matrix.Scale(getOOTScale(obj.ootActorScale), 4) + + try: + # exportPath, levelName = getPathAndLevel(context.scene.geoCustomExport, + # context.scene.geoExportPath, context.scene.geoLevelName, + # context.scene.geoLevelOption) + + saveTextures = context.scene.saveTextures + exportSettings = context.scene.fast64.oot.DLExportSettings + + ootConvertMeshToC( + obj, + finalTransform, + DLFormat.Static, + saveTextures, + exportSettings, + ) + + self.report({"INFO"}, "Success!") + return {"FINISHED"} + + except Exception as e: + if context.mode != "OBJECT": + object.mode_set(mode="OBJECT") + raisePluginError(self, e) + return {"CANCELLED"} # must return a set oot_dl_writer_classes = ( diff --git a/fast64_internal/z64/scene/operators.py b/fast64_internal/z64/scene/operators.py index 3e8da108a..83c0968f1 100644 --- a/fast64_internal/z64/scene/operators.py +++ b/fast64_internal/z64/scene/operators.py @@ -7,7 +7,7 @@ from bpy.ops import object from mathutils import Matrix, Vector -from ...utility import PluginError, raisePluginError, ootGetSceneOrRoomHeader +from ...utility import PluginError, ExportUtils, raisePluginError, ootGetSceneOrRoomHeader from ..utility import ExportInfo, RemoveInfo, sceneNameFromID, is_hackeroot from ..constants import ootEnumMusicSeq, ootEnumSceneID from ..importer import parseScene @@ -119,87 +119,88 @@ class OOT_ExportScene(Operator): bl_options = {"REGISTER", "UNDO", "PRESET"} def execute(self, context): - activeObj = None - try: - if context.mode != "OBJECT": - object.mode_set(mode="OBJECT") - activeObj = context.view_layer.objects.active - - obj = context.scene.ootSceneExportObj - if obj is None: - raise PluginError("Scene object input not set.") - elif obj.type != "EMPTY" or obj.ootEmptyType != "Scene": - raise PluginError("The input object is not an empty with the Scene type.") - - scaleValue = context.scene.ootBlenderScale - finalTransform = Matrix.Diagonal(Vector((scaleValue, scaleValue, scaleValue))).to_4x4() - - except Exception as e: - raisePluginError(self, e) - return {"CANCELLED"} - try: - settings = context.scene.ootSceneExportSettings - levelName = settings.name - option = settings.option - - bootOptions = context.scene.fast64.oot.bootupSceneOptions - is_hackeroot_features = is_hackeroot() - - if settings.customExport: - isCustomExport = True - exportPath = bpy.path.abspath(settings.exportPath) - customSubPath = None - else: - if option == "Custom": - customSubPath = "assets/scenes/" + settings.subFolder + "/" - else: - levelName = sceneNameFromID(option) + with ExportUtils() as export_utils: + activeObj = None + try: + if context.mode != "OBJECT": + object.mode_set(mode="OBJECT") + activeObj = context.view_layer.objects.active + + obj = context.scene.ootSceneExportObj + if obj is None: + raise PluginError("Scene object input not set.") + elif obj.type != "EMPTY" or obj.ootEmptyType != "Scene": + raise PluginError("The input object is not an empty with the Scene type.") + + scaleValue = context.scene.ootBlenderScale + finalTransform = Matrix.Diagonal(Vector((scaleValue, scaleValue, scaleValue))).to_4x4() + + except Exception as e: + raisePluginError(self, e) + return {"CANCELLED"} + try: + settings = context.scene.ootSceneExportSettings + levelName = settings.name + option = settings.option + + bootOptions = context.scene.fast64.oot.bootupSceneOptions + is_hackeroot_features = is_hackeroot() + + if settings.customExport: + isCustomExport = True + exportPath = bpy.path.abspath(settings.exportPath) customSubPath = None - isCustomExport = False - exportPath = bpy.path.abspath(context.scene.ootDecompPath) - - exportInfo = ExportInfo( - isCustomExport, - exportPath, - customSubPath, - levelName, - option, - bpy.context.scene.saveTextures, - settings.singleFile, - context.scene.fast64.oot.useDecompFeatures if not is_hackeroot_features else is_hackeroot_features, - bootOptions if is_hackeroot_features else None, - settings.auto_add_room_objects, - ) - - SceneExport.export( - obj, - finalTransform, - exportInfo, - ) - - self.report({"INFO"}, "Success!") - - # don't select the scene - for elem in context.selectable_objects: - elem.select_set(False) - - context.view_layer.objects.active = activeObj - if activeObj is not None: - activeObj.select_set(True) - - return {"FINISHED"} - - except Exception as e: - if context.mode != "OBJECT": - object.mode_set(mode="OBJECT") - # don't select the scene - for elem in context.selectable_objects: - elem.select_set(False) - context.view_layer.objects.active = activeObj - if activeObj is not None: - activeObj.select_set(True) - raisePluginError(self, e) - return {"CANCELLED"} + else: + if option == "Custom": + customSubPath = "assets/scenes/" + settings.subFolder + "/" + else: + levelName = sceneNameFromID(option) + customSubPath = None + isCustomExport = False + exportPath = bpy.path.abspath(context.scene.ootDecompPath) + + exportInfo = ExportInfo( + isCustomExport, + exportPath, + customSubPath, + levelName, + option, + bpy.context.scene.saveTextures, + settings.singleFile, + context.scene.fast64.oot.useDecompFeatures if not is_hackeroot_features else is_hackeroot_features, + bootOptions if is_hackeroot_features else None, + settings.auto_add_room_objects, + ) + + SceneExport.export( + obj, + finalTransform, + exportInfo, + ) + + self.report({"INFO"}, "Success!") + + # don't select the scene + for elem in context.selectable_objects: + elem.select_set(False) + + context.view_layer.objects.active = activeObj + if activeObj is not None: + activeObj.select_set(True) + + return {"FINISHED"} + + except Exception as e: + if context.mode != "OBJECT": + object.mode_set(mode="OBJECT") + # don't select the scene + for elem in context.selectable_objects: + elem.select_set(False) + context.view_layer.objects.active = activeObj + if activeObj is not None: + activeObj.select_set(True) + raisePluginError(self, e) + return {"CANCELLED"} class OOT_RemoveScene(Operator): diff --git a/fast64_internal/z64/skeleton/operators.py b/fast64_internal/z64/skeleton/operators.py index 5cdef0137..1032306be 100644 --- a/fast64_internal/z64/skeleton/operators.py +++ b/fast64_internal/z64/skeleton/operators.py @@ -4,7 +4,7 @@ from bpy.path import abspath from mathutils import Matrix from ...f3d.f3d_gbi import DLFormat -from ...utility import PluginError, raisePluginError +from ...utility import PluginError, ExportUtils, raisePluginError from ..utility import getStartBone, getNextBone, getOOTScale from ..exporter.skeleton import ootConvertArmatureToC from .importer import ootImportSkeletonC @@ -94,44 +94,47 @@ class OOT_ExportSkeleton(Operator): # Called on demand (i.e. button press, menu item) # Can also be called from operator search menu (Spacebar) def execute(self, context): - armatureObj = None - if context.mode != "OBJECT": - object.mode_set(mode="OBJECT") - if len(context.selected_objects) == 0: - raise PluginError("Armature not selected.") - armatureObj = context.active_object - if armatureObj.type != "ARMATURE": - raise PluginError("Armature not selected.") - - if len(armatureObj.children) == 0 or not isinstance(armatureObj.children[0].data, Mesh): - raise PluginError("Armature does not have any mesh children, or " + "has a non-mesh child.") - - obj = armatureObj.children[0] - finalTransform = Matrix.Scale(getOOTScale(armatureObj.ootActorScale), 4) - - # Rotation must be applied before exporting skeleton. - # For some reason this does not work if done on the duplicate generated later, so we have to do it before then. - object.select_all(action="DESELECT") - armatureObj.select_set(True) - object.transform_apply(location=False, rotation=True, scale=True, properties=False) - object.select_all(action="DESELECT") - - try: - exportSettings: OOTSkeletonExportSettings = context.scene.fast64.oot.skeletonExportSettings - - saveTextures = context.scene.saveTextures - drawLayer = armatureObj.ootDrawLayer - - ootConvertArmatureToC(armatureObj, finalTransform, DLFormat.Static, saveTextures, drawLayer, exportSettings) - - self.report({"INFO"}, "Success!") - return {"FINISHED"} - - except Exception as e: + with ExportUtils() as export_utils: + armatureObj = None if context.mode != "OBJECT": object.mode_set(mode="OBJECT") - raisePluginError(self, e) - return {"CANCELLED"} # must return a set + if len(context.selected_objects) == 0: + raise PluginError("Armature not selected.") + armatureObj = context.active_object + if armatureObj.type != "ARMATURE": + raise PluginError("Armature not selected.") + + if len(armatureObj.children) == 0 or not isinstance(armatureObj.children[0].data, Mesh): + raise PluginError("Armature does not have any mesh children, or " + "has a non-mesh child.") + + obj = armatureObj.children[0] + finalTransform = Matrix.Scale(getOOTScale(armatureObj.ootActorScale), 4) + + # Rotation must be applied before exporting skeleton. + # For some reason this does not work if done on the duplicate generated later, so we have to do it before then. + object.select_all(action="DESELECT") + armatureObj.select_set(True) + object.transform_apply(location=False, rotation=True, scale=True, properties=False) + object.select_all(action="DESELECT") + + try: + exportSettings: OOTSkeletonExportSettings = context.scene.fast64.oot.skeletonExportSettings + + saveTextures = context.scene.saveTextures + drawLayer = armatureObj.ootDrawLayer + + ootConvertArmatureToC( + armatureObj, finalTransform, DLFormat.Static, saveTextures, drawLayer, exportSettings + ) + + self.report({"INFO"}, "Success!") + return {"FINISHED"} + + except Exception as e: + if context.mode != "OBJECT": + object.mode_set(mode="OBJECT") + raisePluginError(self, e) + return {"CANCELLED"} # must return a set oot_skeleton_classes = (