I just had a quick question about providing undo via your API.
I'm using all the code that you provided just like taught in your samples but when I make a pretty involved operator using your APII think the reason that I'm not able to undo my operator when I run it is because I am calling an external API
i'm not really versed in this could you let me know if there's something you could provide or have provided that would allow users of your api to undo operations when they're creating an operator from your functions.
Comments (6)
-
repo owner -
repo owner - changed status to open
-
reporter OKI already knew about BL options undo ……………are you saying that the actual contents of BL options should contain undo and that preset… which I've never seen before…. Or is it just your common coding practice to use the preset item in BL options and you're just showing me about the undo… just to note that I already use undo and the Register item in my BL options and it doesn't allow for undoing code written with your operators called in class methods….and the execute function
-
repo owner No, you can add one or the other, or other keywords as well. The PRESET keyword enables operator presets, UNDO enables undo.
-
reporter So does the preset button fix it? If it doesn't that still brings me back to the issue that the API for DIFFEOMORPHIC should in theory Allow undoing code when you run operators from it inside another operator do you have any relevant functions for the operators that you provide in the API that are not class methods because I noticed that my undo was hampered when that was the case have you added register undo to all the operators that you provide in your api is there a chance you could check that because I don't have any issue on doing actions that have my own operators inside an operator if both have you know the undo bl option and all of the relevant functions are class methods …..now not sure the issue is on your end though this was GPT 's guess as one of 5 possibilities I just saw it important to bring to your attention you know essentially I'm only running easy import as and import action and merge rigs… Is there a chance she could scan my code and let me know if there's any way that I've set up the DIFFEOMORPHIC functionality wrong to where when I run this code which I think is written right undo isn't available.….. Then we could figure out whether the issue is on your end my end or maybe it's just some sort of weird blender python anomaly I haven't witnessed something like that but G P T suggests that that could happen too...
class FAST_OT_diffeomorphic_import(bpy.types.Operator): """Internal...Used to import DAZ STUDIO assets""" bl_idname = "fast.diffeomorphic_import" bl_label = "Diffeomorphic Import" bl_options = {"REGISTER", "UNDO"} file_path: bpy.props.StringProperty(subtype="FILE_PATH") def select_object(obj): try: bpy.ops.object.select_all(action="DESELECT") obj.select_set(True) bpy.context.view_layer.objects.active = obj except: return False return True def set_mode(self, mode): if bpy.context.object and bpy.context.object.mode != mode: try: bpy.ops.object.mode_set(mode=mode) except: return False return True def get_highest_empty(self, empty1, empty2): """Returns the empty with the higher Z value and the other empty.""" if empty1.location.z > empty2.location.z: return empty1, empty2 return empty2, empty1 def get_diffeomorphic_paths_two(self): # Base directory for Blender's scripts scripts_path = bpy.utils.resource_path("USER") addon_folder = "FAST" # Base directory for addon base_addon_directory = os.path.join( scripts_path, "scripts", "addons", addon_folder ) # Construct the various directory paths pose_save_directory_path = os.path.join( base_addon_directory, "daz_studio_save", "pose" ) settings_path = os.path.join( base_addon_directory, "diffeomorphic_settings", "EVEE.json" ) temp_settings_path = os.path.join( base_addon_directory, "diffeomorphic_settings", "temp.json" ) return pose_save_directory_path, settings_path, temp_settings_path def delete_files(self): try: manager = bpy.context.preferences.addons[__name__].preferences.Prop for file_path in [ manager.diffeomorphic_object_duf, manager.diffeomorphic_object_dbz, manager.diffeomorphic_object_duf_png, manager.diffeomorphic_pose_duf, manager.diffeomorphic_pose_duf_png, manager.diffeomorphic_audio_file, ]: if file_path: try: os.remove(file_path) print_color("AB", "\nDeleted file:") print_color("AR", f"{file_path}") except Exception as e: captured_traceback = get_exception_traceback_str(e) if ( ".wav" in captured_traceback or ".mp3" in captured_traceback or ".ogg" in captured_traceback ): manager.diffeomorphic_allow_information = 1 else: manager.diffeomorphic_allow_information = 2 print_color("AB", "Failed to delete file:") print_color("AR", f"{file_path} - {e}") # This will print the captured traceback, decorated with '=' lines for clarity print("") print("\nCaptured Traceback:\n") print(captured_traceback) except OSError as e: if e.errno == 13: # PermissionError print(f"\nPermission denied when trying to delete file: {file_path}") manager.monitor_daz_studio_save_directory = False else: print(f"\nFailed to delete file_2: {file_path} - {e}") manager.monitor_daz_studio_save_directory = False # dffF def detect_hair_advanced(self): potential_hair_objects = set() # Original logic for detection using object name and polygon count. for obj in bpy.data.objects: if obj.type == "MESH" and ( "hair" in obj.name.lower() and len(obj.data.polygons) > 30000 ): potential_hair_objects.add(obj) # Advanced check for detection using image texture node names. for obj in bpy.data.objects: if obj.type == "MESH": for slot in obj.material_slots: if "hair" in slot.name.lower() and not ( "eyebrow" in slot.name.lower() or "eyelash" in slot.name.lower() ): potential_hair_objects.add(obj) continue if slot.material: for node in slot.material.node_tree.nodes: if ( isinstance(node, bpy.types.ShaderNodeTexImage) and node.image and "hair" in node.image.name.lower() ): potential_hair_objects.add(obj) break for vg in obj.vertex_groups: if "hair" in vg.name.lower() and not ( "eyebrow" in vg.name.lower() or "eyelash" in vg.name.lower() ): potential_hair_objects.add(obj) break return potential_hair_objects # Return the set of detected hair objects def disable_hair(self, collection_name): manager = bpy.context.preferences.addons[__name__].preferences.Prop print("Disabling hair...") if manager.diffeomorphic_disable_hair: potential_hair_objects = self.detect_hair_advanced() for ob in bpy.data.collections[collection_name].objects: if potential_hair_objects is not None: if ob in potential_hair_objects: poly_count = len(ob.data.polygons) if poly_count > 30000: ob.hide_viewport = True print( f"'{ob.name}' with {poly_count} polygons is hidden in the viewport." ) def get_collection_name(self): manager = bpy.context.preferences.addons[__name__].preferences.Prop try: # Get the current active object rig = bpy.context.view_layer.objects.active # Check if there's no active object or if the active object isn't an armature if not rig or rig.type != "ARMATURE": print( f"No active rig or the active object is not an armature. Active object: {rig.name if rig else 'None'}" ) return None # Get the collections the rig is a part of rig_collections = rig.users_collection # If the rig is part of any collection, return the name of the last one if rig_collections: return rig_collections[-1].name except Exception as e: print(f"An error occurred in get_collection_name: {e}") manager.monitor_daz_studio_save_directory = False return None def merge_rigs(self): manager = bpy.context.preferences.addons[__name__].preferences.Prop print("Merging rigs...") # Get the collection name collection_name = self.get_collection_name() # Deselect all objects if manager.diffeomorphic_disable_hair: self.disable_hair(collection_name) bpy.ops.object.select_all(action="DESELECT") # Select all armatures in characters collection for ob in bpy.data.collections[collection_name].objects: if ob.type == "ARMATURE": print("Armature Name:", ob.name) # Ensure the object can be selected ob.hide_select = False ob.select_set(True) # Find the rig with a corresponding mesh in the collection rig = None for obj in bpy.data.collections[collection_name].objects: if obj.type == "ARMATURE": rig_name = obj.name print("Rig Name:", rig_name) mesh_name = rig_name + " Mesh" print("Mesh Name:", mesh_name) if bpy.data.objects.get(mesh_name): rig = obj break if rig: print("Rig found:", rig.name) bpy.context.view_layer.objects.active = rig try: # Merge rigs print("Merging rigs - Starting merge operation") bpy.ops.daz.merge_rigs( separateCharacters=manager.diffeomorphic_separate_characters, useMergeNonConforming=manager.diffeomorphic_merge_non_conforming, ) print("Merging rigs - Merge operation completed") except ModuleNotFoundError: print("The 'import_daz' module was not found!") return {"CANCELLED"} else: print("Rig not found") def setup_camera_on_head(self): manager = bpy.context.preferences.addons[__name__].preferences.Prop # Set the scene to frame 1 bpy.context.scene.frame_set(1) # Ensure we are in object mode if not self.set_mode("OBJECT"): return if ( not bpy.context.active_object or bpy.context.active_object.type != "ARMATURE" ): raise ValueError("Armature not selected.") armature = bpy.context.active_object # Additional checks: # 1. Verify that the armature has a bone named "head" if "head" not in armature.pose.bones: print("The selected armature doesn't have a bone named 'head'.") bpy.ops.fast.hide_console() draw_centered_info( "Import Errors?? Be sure you added your DAZ Asset Libraries.", width=326 ) return # Get global coordinates of the head and tail of the "head" bone head_bone = armature.pose.bones["head"] head_global = armature.matrix_world @ head_bone.head tail_global = armature.matrix_world @ head_bone.tail # Add empties bpy.ops.object.empty_add(location=head_global) empty_head = bpy.context.active_object bpy.ops.object.empty_add(location=tail_global) empty_tail = bpy.context.active_object # Determine higher empty and delete the lower one higher_empty, lower_empty = self.get_highest_empty(empty_head, empty_tail) bpy.data.objects.remove(lower_empty, do_unlink=True) # Switch back to object mode to add and set up the camera # Ensure we are in object mode if not self.set_mode("OBJECT"): return bpy.ops.object.camera_add() self.camera = bpy.context.active_object bpy.context.scene.camera = self.camera self.camera.data.show_passepartout = True self.camera.data.passepartout_alpha = 1.0 # Set the camera's location and rotation based on the higher empty's position self.camera.location = higher_empty.location self.camera.rotation_euler.x = 1.5708 # 90 degrees in radians # Zero out the camera's location values after positioning self.camera.location.x -= manager.diffeomorphic_camera_x_offset self.camera.location.y -= ( manager.diffeomorphic_camera_y_offset ) # Offset in the negative Y direction # Delete the higher empty bpy.data.objects.remove(higher_empty, do_unlink=True) print("All operations completed.") def finishing_character(self, context, save_path): # # try: manager = bpy.context.preferences.addons[__name__].preferences.Prop # Get the active object rig = bpy.context.active_object # your rig object # Check if the active object is indeed an armature if not isinstance(rig, bpy.types.Object) or rig.type != "ARMATURE": print_color("AR", "\nSelected object is not a rig!") return False # Check if the rig is a Genesis rig if is_genesis_rig(rig, adjust_print=True): # The function will print the rig type if it is a Genesis rig pass else: print_color("AR", "Not a Genesis rig!\n") # Get the location of the character's rig rig_location = rig.location.copy() # Store the current active collection current_collection = bpy.context.view_layer.active_layer_collection # Switch to the Scene Collection bpy.context.view_layer.active_layer_collection = ( bpy.context.view_layer.layer_collection ) # Generate a unique name for the empty object unique_name = rig.name + "_empty_" + str(uuid.uuid4())[:8] # Check if the object name already exists in the 'Scene Collection' scene_collection = bpy.context.scene.collection if unique_name not in scene_collection.objects: # If not, create the empty bpy.ops.object.empty_add(type="PLAIN_AXES", location=rig_location) empty = bpy.context.active_object empty.name = unique_name print("Empty.name:", empty.name) else: print( f"Object {unique_name} already exists in Scene Collection. Skipping addition." ) empty = scene_collection.objects[unique_name] # Switch back to the original active collection bpy.context.view_layer.active_layer_collection = current_collection # Parent the rig to the empty rig.select_set(True) empty.select_set(True) bpy.context.view_layer.objects.active = empty bpy.ops.object.parent_set(type="OBJECT") bpy.ops.object.select_all(action="DESELECT") empty.select_set(True) ### ADD MULTIPLE LIGHT SETUP # Check if the collection "FAST Lighting Setup" doesn't exist in the scene if "FAST Lighting Setup" not in bpy.data.collections: bpy.ops.fast.multiple_light_setup() if manager.optimized_map: bpy.ops.fast.custom_normal(custom=True) if manager.daz_studio_extra_setup == True: bpy.ops.fast.save_and_enter_material_preview_mode() for area in bpy.context.screen.areas: if area.type == "VIEW_3D": for space in area.spaces: if space.type == "VIEW_3D": # Turn off overlays space.overlay.show_overlays = False # Turn on Scene Lights and Scene World if they're off if not space.shading.use_scene_lights_render: space.shading.use_scene_lights_render = True if not space.shading.use_scene_world_render: space.shading.use_scene_world_render = True break scene = bpy.context.scene transparent = scene.render.film_transparent = True print("\nTransparency set = ", transparent) bpy.ops.object.select_all(action="DESELECT") rig.select_set(True) bpy.context.view_layer.objects.active = rig try: self.setup_camera_on_head() except Exception as e: manager.monitor_daz_studio_save_directory = False print(f"An unexpected error occurred: {e}") return False # # Ensure the camera is selected (it should be if the previous function worked as intended) self.camera.select_set(True) # Select the rig as well rig.select_set(True) # Select the empty empty.select_set(True) # Set the empty as the active object bpy.context.view_layer.objects.active = empty # Now, parent both selected objects (camera and rig) to the active object (empty) bpy.ops.object.parent_set(type="OBJECT") # Deselect all objects bpy.ops.object.select_all(action="DESELECT") # Set the empty as the active object again if needed bpy.context.view_layer.objects.active = self.camera for window in bpy.context.window_manager.windows: screen = window.screen for area in screen.areas: if area.type == "VIEW_3D": # Find the WINDOW region within the 3D View area region = next((r for r in area.regions if r.type == "WINDOW"), None) if region: # Prepare the override context for the 3D view override = bpy.context.copy() override["window"] = window override["screen"] = screen override["area"] = area override["region"] = region # override["space_data"] = area.spaces.active # Set the active camera and object bpy.context.scene.camera = self.camera bpy.context.view_layer.objects.active = self.camera self.camera.select_set(True) with bpy.context.temp_override(**override): time.sleep(0.5) # Half a second delay bpy.ops.view3d.view_camera() bpy.ops.view3d.view_center_camera() # Store the original view matrix view_matrix = context.region_data.view_matrix.copy() # Execute the view operations bpy.ops.view3d.view_all() bpy.ops.view3d.view_lock_clear() # Restore the original view matrix context.region_data.view_matrix = view_matrix area.spaces.active.region_3d.view_perspective = "CAMERA" # Set the default message text = "No Face Anim?? Enable All Morphs & Read Morphs Tooltips.\nImport Errors?? Be sure you added your DAZ Asset Libraries." if manager.diffeomorphic_allow_information == 1: # Additional text and formatting are added if diffeomorphic_allow_information equals 1 additional_text = ( "=================================================\n" "ERROR: Cannot delete audio file. It's likely in use by DAZ Studio.\n" "Close DAZ Studio & delete audio file manually from DAZ_STUDIO_SAVE/AUDIO folder.\n" "Your backup is SAFE, backup op copies files, circumventing 'file in use' error." "\n==================================================" ) full_text = f"{text}\n{additional_text}" manager.diffeomorphic_allow_information = 0 bpy.ops.fast.hide_console() # Call draw_centered_info with wider width and offset for full message draw_centered_info(full_text, width=475) elif manager.diffeomorphic_allow_information == 2: text = ( f"{text}\n" "====================================\n" "ERROR: Unexpected issue here! Please check System Console!" "\n====================================" ) manager.diffeomorphic_allow_information = 0 bpy.ops.fast.hide_console() draw_centered_info(text, width=326) else: bpy.ops.fast.hide_console() draw_centered_info(text, width=330) manager.monitor_daz_studio_save_directory = False bpy.ops.wm.save_as_mainfile(filepath=save_path) # except Exception as e: # manager.monitor_daz_studio_save_directory = False # print("Error in finishing character:", e) # return False return True def finishing_environment( self, duf_file_start_path, dbz_file_start_path, duf_png_file_start_path, duf_file_name_without_ext, temp_settings_path, ): manager = bpy.context.preferences.addons[__name__].preferences.Prop # Set the manager variables manager.diffeomorphic_object_duf = duf_file_start_path manager.diffeomorphic_object_dbz = dbz_file_start_path manager.diffeomorphic_object_duf_png = duf_png_file_start_path manager.diffeomorphic_pose_duf = "" manager.diffeomorphic_pose_duf_png = "" manager.diffeomorphic_audio_file = "" manager.diffeomorphic_file_name = duf_file_name_without_ext # resetting back to their original state, they were both set to false in the monitor function manager.diffeomorphic_import_action = manager.diffeomorphic_import_action_temp manager.diffeomorphic_add_audio = manager.diffeomorphic_add_audio_temp print("") bpy.ops.wm.save_userpref() try: # Check if there's an active object and if it has bones attribute rig = bpy.context.active_object # your rig object if rig and hasattr(rig, "bones"): if is_genesis_rig(rig): print_color( "RW", "To successfully import GENESIS...Set MESH FITTING to DBZ FILE on panel.", shift=True, ) print_color( "RW", "Your files are still safely inside DAZ Studio save folderready to be reimported.", shift=True, ) manager.monitor_daz_studio_save_directory = False if manager.re_import_in_progress: self.delete_files() manager.re_import_in_progress = False return False if manager.re_import_in_progress: self.delete_files() manager.re_import_in_progress = False else: backup_and_zip_files() if manager.diffeomorphic_object_duf: print_color("AG", "\nmanager.diffeomorphic_object_duf:") print_color("AR", f"{manager.diffeomorphic_object_duf}\n") if manager.diffeomorphic_object_dbz: print_color("AG", "manager.diffeomorphic_object_dbz:") print_color("AR", f"{manager.diffeomorphic_object_dbz}\n") if manager.diffeomorphic_object_duf_png: print_color("AG", "manager.diffeomorphic_object_duf_png:") print_color("AR", f"{manager.diffeomorphic_object_duf_png}\n") # print("") try: if manager.diffeomorphic_load_fast_settings: # Restore the original settings file if os.path.exists(temp_settings_path): # Load the temporary settings file bpy.ops.daz.load_settings_file(filepath=temp_settings_path) print_color("AB", "\nTemp settings loaded:") # Delete the temporary settings file if os.path.exists(temp_settings_path): os.remove(temp_settings_path) print_color("AB", "\nTemporary settings deleted.") else: print_color("AR", "\nTemporary settings not found:") except Exception as ex: traceback.print_exc() self.report({"ERROR"}, f"Error occurred while restoring settings: {ex}") manager.monitor_daz_studio_save_directory = False return False if manager.optimized_map: bpy.ops.fast.custom_normal(custom=True) if manager.daz_studio_extra_setup == True: bpy.ops.fast.save_and_enter_material_preview_mode() for area in bpy.context.screen.areas: if area.type == "VIEW_3D": for space in area.spaces: if space.type == "VIEW_3D": # Turn off overlays space.overlay.show_overlays = False # Turn on Scene Lights and Scene World if they're off if not space.shading.use_scene_lights_render: space.shading.use_scene_lights_render = True if not space.shading.use_scene_world_render: space.shading.use_scene_world_render = True break scene = bpy.context.scene transparent = scene.render.film_transparent = True print("\nTransparency set = ", transparent) print_color( "AR", "\nERROR: Be sure you added your DAZ Asset Libraries in the DAZ STUDIO tab of FAST Preferences.", ) if manager.diffeomorphic_reminders: bpy.ops.fast.hide_console() draw_centered_info( "Import Errors?? Be sure you added your DAZ Asset Libraries.", width=350, ) manager.monitor_daz_studio_save_directory = False pass except Exception as e: manager.monitor_daz_studio_save_directory = False print("Error in finishing environment:", e) return False return True def execute(self, context): try: import import_daz except ModuleNotFoundError: self.report({"ERROR"}, "The 'import_daz' module was not found!") manager.monitor_daz_studio_save_directory = False return {"CANCELLED"} bpy.ops.fast.show_console() manager = context.preferences.addons[__name__].preferences.Prop fps = float(manager.diffeomorphic_fps) for window in bpy.context.window_manager.windows: for area in window.screen.areas: area.tag_redraw() # Now use the function to get all the paths ( pose_save_directory_path, settings_path, temp_settings_path, ) = self.get_diffeomorphic_paths_two() # Set the directory to the folder where this blend file is saved auto_save_path = bpy.data.filepath directory = os.path.dirname(auto_save_path) # If file unsaved then directory will be "" if directory == "": # Set the directory to the user's desktop directory = os.path.join(os.path.expanduser("~"), "Desktop") file_name = bpy.path.basename(bpy.context.blend_data.filepath) if file_name == "": file_name = "diffeomorphic_import_save.blend" save_path = os.path.join(directory, file_name) # print('save_path:', save_path) else: save_path = auto_save_path bpy.ops.wm.save_as_mainfile(filepath=save_path) try: if manager.diffeomorphic_load_fast_settings: # Handling temp_settings_path if os.path.exists(temp_settings_path): os.remove(temp_settings_path) # Save the current settings to a temporary file bpy.ops.daz.save_settings_file( filepath=temp_settings_path, check_existing=False ) print_color("AB", "\nTemporary settings path:\n", temp_settings_path) print_color("AB", "\nSettings path:\n", settings_path, "\n") # Load your desired settings file if os.path.exists(settings_path): bpy.ops.daz.load_settings_file(filepath=settings_path) print_color("AB", "\nCustom settings loaded.") else: print_color("AR", "\nCustom settings not found.") except AttributeError as ae: if "bpy.ops.daz.save_settings_file" in str( ae ) and "could not be found" in str(ae): print( "Enable DIFFEOMORPHIC in Blender add-on preferences and try again", 312, ) else: # For any other AttributeError not related to daz.save_settings_file traceback.print_exc() self.report( {"ERROR"}, f"Error occurred while processing settings: {ae}" ) manager.monitor_daz_studio_save_directory = False return {"CANCELLED"} except Exception as ex: traceback.print_exc() self.report({"ERROR"}, f"Error occurred while processing settings: {ex}") manager.monitor_daz_studio_save_directory = False return {"CANCELLED"} # print("manager.diffeomorphic", manager.diffeomorphic) if manager.diffeomorphic: if self.file_path: duf_file_start_path = self.file_path # Extract the filename from the file path duf_file_base_name = os.path.basename(duf_file_start_path) # Extract the directory path and the file name orig_duf_file_dir_path = os.path.dirname(duf_file_start_path) # Remove the existing extension duf_file_name_without_ext = os.path.splitext(duf_file_base_name)[0] dbz_file_base_name = duf_file_name_without_ext + ".dbz" duf_png_file_base_name = duf_file_name_without_ext + ".duf.png" dbz_file_start_path = os.path.join( orig_duf_file_dir_path, dbz_file_base_name ) duf_png_file_start_path = os.path.join( orig_duf_file_dir_path, duf_png_file_base_name ) if manager.diffeomorphic_import_action == True: # Check for DUF files in the 'POSE' subdirectory pose_dir = os.path.join(orig_duf_file_dir_path, "pose") # If 'POSE' directory doesn't exist create one & return from function, then folder set up right, But we return because no Pose Preset was there if not os.path.isdir(pose_dir): # Create the 'POSE' directory if it doesn't exist os.makedirs(pose_dir) print( "No 'POSE' subdirectory found. I made one for you, Save a Pose Preset there & try again" ) manager.monitor_daz_studio_save_directory = False return {"CANCELLED"} pose_files = [ f for f in os.listdir(pose_dir) if f.lower().endswith(".duf") ] pose_dir = pose_dir.replace("\\", "/") # Find .duf files in the directory pose_files = [ f for f in os.listdir(pose_dir) if f.lower().endswith(".duf") ] print_color("AG", f"\nFound POSE files: {pose_files}", new_line=True) print_color("AG", f"\nBeginning DAZ import...", new_line=True) if len(pose_files) != 1: # bpy.ops.fast.pose_message_box('INVOKE_DEFAULT') manager.monitor_daz_studio_save_directory = False return {"CANCELLED"} action_file = os.path.join(pose_dir, pose_files[0]).replace("\\", "/") try: import_daz.set_silent_mode(False) import_daz.set_selection([duf_file_start_path]) except ModuleNotFoundError: self.report({"ERROR"}, "The 'import_daz' module was not found!") manager.monitor_daz_studio_save_directory = False return {"CANCELLED"} while not os.path.exists(dbz_file_start_path): time.sleep(1) # Sleep for 1 second before checking again import re # Regular expression module for pattern searching is_genesis = is_character_file(duf_file_start_path) try: if manager.diffeomorphic_fit_meshes in ["SHARED", "UNIQUE"]: print_color("AG", "\nAttempting", new_line=False) print_color("AB", " easy_import_daz ", new_line=False) print_color("AG", "with", new_line=False) print_color("AR", " MESH FITTING ", new_line=False) print_color("AG", "setting as ", new_line=False) print_color("AR", manager.diffeomorphic_fit_meshes) if is_genesis == True: print_color( "AR", "\nMESH FITTING setting is 'UNIQUE/SHARED' and this is a Genesis character. Canceling function.", ) manager.monitor_daz_studio_save_directory = False manager.re_import_in_progress = False return {"CANCELLED"} bpy.ops.daz.easy_import_daz( fitMeshes=manager.diffeomorphic_fit_meshes ) elif manager.diffeomorphic_fit_meshes in ["MORPHED", "DBZFILE"]: print_color("AG", "\nAttempting", new_line=False) print_color("AB", " easy_import_daz ", new_line=False) print_color("AG", "with", new_line=False) print_color("AR", " MESH FITTING ", new_line=False) print_color("AG", "setting as ", new_line=False) print_color("AR", manager.diffeomorphic_fit_meshes) if is_genesis == False: print_color( "AR", "\nMESH FITTING setting is 'MORPHED/DBZFILE' and this is not a Genesis character. Canceling function.\n", ) manager.monitor_daz_studio_save_directory = False manager.re_import_in_progress = False return {"CANCELLED"} bpy.ops.daz.easy_import_daz( useUnits=manager.diffeomorphic_units, useExpressions=manager.diffeomorphic_expressions, useVisemes=manager.diffeomorphic_visemes, useBody=manager.diffeomorphic_body, useFacs=manager.diffeomorphic_facs, useFacsdetails=manager.diffeomorphic_facs_details, useFacsexpr=manager.diffeomorphic_facs_expressions, fitMeshes=manager.diffeomorphic_fit_meshes, ) else: return {"CANCELLED"} print("\nDAZ operation completed successfully!") except Exception as e: error_messages = traceback.format_exc() print("\nError Encountered:\n", error_messages) manager.monitor_daz_studio_save_directory = False # Resetting back here in case of an exception manager.diffeomorphic_import_action = ( manager.diffeomorphic_import_action_temp ) manager.diffeomorphic_add_audio = manager.diffeomorphic_add_audio_temp print("\nReset the properties...\n") # If neither 'MORPHED' nor 'DBZFILE' are selected for fitMeshes, use the operator with only fitMeshes. if manager.diffeomorphic_fit_meshes in ["MORPHED", "DBZFILE"]: collection_name = self.get_collection_name() if collection_name is None: print_color( "AR", "\nERROR: Be sure you added your DAZ Asset Libraries in the DAZ STUDIO tab of FAST Preferences.", ) manager.monitor_daz_studio_save_directory = False return {"CANCELLED"} result = self.merge_rigs() if result == {"CANCELLED"}: self.report({"ERROR"}, "Rig merging failed!") manager.monitor_daz_studio_save_directory = False return {"CANCELLED"} if manager.diffeomorphic_import_action: # Use the user-specified action name if it's not an empty string if manager.diffeomorphic_action_name != "": actionName = manager.diffeomorphic_action_name.replace(" ", "_") else: # Extract the action name from the pose file without extension action_name_without_ext = os.path.splitext(pose_files[0])[0] # Remove spaces in the action name action_name_without_ext = action_name_without_ext.replace( " ", "_" ) # Use the extracted action name actionName = action_name_without_ext try: import_daz.set_selection([action_file]) bpy.ops.daz.import_action( fps=fps, firstFrame=manager.diffeomorphic_first_frame, lastFrame=manager.diffeomorphic_last_frame, makeNewAction=True, actionName=actionName, ) except ModuleNotFoundError: self.report({"ERROR"}, "The 'import_daz' module was not found!") manager.monitor_daz_studio_save_directory = False return {"CANCELLED"} # Copy and move any pose file to bak for f in pose_files: manager.diffeomorphic_pose_duf = os.path.join( pose_save_directory_path, f ) pose_png_files = [ f for f in os.listdir(pose_dir) if f.lower().endswith(".duf.png") ] for f in pose_png_files: pose_png_file_path = os.path.join(pose_dir, f) if os.path.isfile(pose_png_file_path): manager.diffeomorphic_pose_duf_png = os.path.join( pose_save_directory_path, f ) else: print( f"\nPOSE DUF.PNG file: {f} not found. Skipping move operation." ) else: manager.diffeomorphic_pose_duf = "" manager.diffeomorphic_pose_duf_png = "" # Set the manager variables manager.diffeomorphic_object_duf = duf_file_start_path manager.diffeomorphic_object_dbz = dbz_file_start_path manager.diffeomorphic_object_duf_png = duf_png_file_start_path manager.diffeomorphic_file_name = duf_file_name_without_ext if manager.re_import_in_progress: print("Re-import in progress...") self.delete_files() manager.re_import_in_progress = False else: print("Re-import not in progress...") backup_and_zip_files() bpy.context.scene.render.fps = int(fps) # Saving user preferences after the variables printed below are created to make reimport easy print("") bpy.ops.wm.save_userpref() if manager.diffeomorphic_object_duf: print_color("AG", "\nmanager.diffeomorphic_object_duf:") print_color("AR", f"{manager.diffeomorphic_object_duf}\n") if manager.diffeomorphic_object_dbz: print_color("AG", "manager.diffeomorphic_object_dbz:") print_color("AR", f"{manager.diffeomorphic_object_dbz}\n") if manager.diffeomorphic_object_duf_png: print_color("AG", "manager.diffeomorphic_object_duf_png:") print_color("AR", f"{manager.diffeomorphic_object_duf_png}\n") if manager.diffeomorphic_pose_duf: print_color("AG", "manager.diffeomorphic_pose_duf:") print_color("AR", f"{manager.diffeomorphic_pose_duf}\n") elif manager.diffeomorphic_pose_duf_png: print_color("AG", "manager.diffeomorphic_pose_duf_png:") print_color("AR", f"{manager.diffeomorphic_pose_duf_png}\n") else: print_color("AR", "No animation added\n") if manager.diffeomorphic_audio_file: print_color("AG", "manager.diffeomorphic_audio_file:") print_color("AR", f"{manager.diffeomorphic_audio_file}\n") else: print_color("AR", "No audio added\n") try: if manager.diffeomorphic_load_fast_settings: # Restore the original settings file if os.path.exists(temp_settings_path): # Load the temporary settings file bpy.ops.daz.load_settings_file(filepath=temp_settings_path) print_color("AG", "\nTemporary settings loaded:") # Delete the temporary settings file if os.path.exists(temp_settings_path): os.remove(temp_settings_path) print_color("AR", "\nTemporary settings deleted.") else: print_color("AR", "\nTemporary settings not found:") except Exception as ex: traceback.print_exc() self.report( {"ERROR"}, f"Error occurred while restoring settings: {ex}" ) manager.monitor_daz_studio_save_directory = False return {"CANCELLED"} if not self.finishing_character(context, save_path): return {"CANCELLED"} else: if not self.finishing_environment( duf_file_start_path, dbz_file_start_path, duf_png_file_start_path, duf_file_name_without_ext, temp_settings_path, ): return {"CANCELLED"} print_color("AG", "\nSaving file to Backup directory as: ", new_line=False) print_color("AR", "daz_studio_import_end.blend") bpy.ops.fast.backup_file( overwrite=True, filename="daz_studio_import_complete.blend" ) return {"FINISHED"} def handled_daz_settings_1(): manager = bpy.context.preferences.addons[__name__].preferences.Prop scripts_path = bpy.utils.resource_path("USER") addon_folder = "FAST" # Base directory for addon base_addon_directory = os.path.join(scripts_path, "scripts", "addons", addon_folder) # Construct the various directory paths settings_path = os.path.join( base_addon_directory, "diffeomorphic_settings", "EVEE.json" ) temp_settings_path = os.path.join( base_addon_directory, "diffeomorphic_settings", "temp.json" ) try: if manager.diffeomorphic_load_fast_settings: # Handling temp_settings_path if os.path.exists(temp_settings_path): os.remove(temp_settings_path) # Save the current settings to a temporary file bpy.ops.daz.save_settings_file( filepath=temp_settings_path, check_existing=False ) print_color("AB", "\nTemporary settings path:\n", temp_settings_path) print_color("AB", "\nSettings path:\n", settings_path, "\n") # Load your desired settings file if os.path.exists(settings_path): bpy.ops.daz.load_settings_file(filepath=settings_path) print_color("AB", "\nCustom settings loaded.") else: print_color("AR", "\nCustom settings not found.") except AttributeError as ae: if "bpy.ops.daz.save_settings_file" in str(ae) and "could not be found" in str( ae ): print( "Enable DIFFEOMORPHIC in Blender add-on preferences and try again", 312 ) else: # For any other AttributeError not related to daz.save_settings_file traceback.print_exc() bpy.context.window_manager.monitor_daz_studio_save_directory = False return {"CANCELLED"} except Exception as ex: traceback.print_exc() bpy.context.window_manager.monitor_daz_studio_save_directory = False return {"CANCELLED"} def handled_daz_settings_2(): manager = bpy.context.preferences.addons[__name__].preferences.Prop scripts_path = bpy.utils.resource_path("USER") addon_folder = "FAST" # Base directory for addon base_addon_directory = os.path.join(scripts_path, "scripts", "addons", addon_folder) # Construct the various directory paths temp_settings_path = os.path.join( base_addon_directory, "diffeomorphic_settings", "temp.json" ) try: if manager.diffeomorphic_load_fast_settings: # Restore the original settings file if os.path.exists(temp_settings_path): # Load the temporary settings file bpy.ops.daz.load_settings_file(filepath=temp_settings_path) print_color("AG", "\nTemporary settings loaded:") # Delete the temporary settings file if os.path.exists(temp_settings_path): os.remove(temp_settings_path) print_color("AR", "\nTemporary settings deleted.\n") else: print_color("AR", "\nTemporary settings not found:") except Exception as ex: traceback.print_exc() bpy.context.window_manager.monitor_daz_studio_save_directory = False return {"CANCELLED"}
-
repo owner - changed status to closed
- Log in to comment
You add the undo feature with bl_options, like this: