#THIS ADDON SETS ALL CORRECT MANUAL FRAME RANGES TO ALL ACTIONS AT ONCE PRESSING JUST ONE BUTTON #MORE INFO: https://www.keviniglesias.com/animationBlenderFiles.html bl_info = { "name": "Kevin Iglesias Manual Frame Range Setter", "author": "Kevin Iglesias (www.keviniglesias.com)", "version": (1, 1), "blender": (4, 1, 0), "location": "3D View > Sidebar > Kevin Iglesias", "description": "Automatically set Manual Frame Range from custom property to all actions", "category": "Animation", } import bpy def set_frame_range(action): end = action.get("animation_end_frame") loop = action.get("animation_loop") if end is None: return False if loop is None: return False action.use_frame_range = True action.frame_start = 1 action.frame_end = end action.use_cyclic = loop > 0 return True class ACTION_OT_apply_current(bpy.types.Operator): bl_idname = "actiontools.apply_current" bl_label = "Apply to Current Action" bl_description = "Enable Manual Frame Range for current action" @classmethod def poll(cls, context): obj = context.object return obj and obj.animation_data and obj.animation_data.action def execute(self, context): action = context.object.animation_data.action if not set_frame_range(action): self.report({'WARNING'}, f"'{action.name}' missing 'animation_end_frame'") else: self.report({'INFO'}, f"Applied to '{action.name}'") return {'FINISHED'} class ACTION_OT_apply_all(bpy.types.Operator): bl_idname = "actiontools.apply_all" bl_label = "Apply to All Actions" bl_description = "Enable Manual Frame Range for all actions" def execute(self, context): failed = [] for action in bpy.data.actions: if not set_frame_range(action): failed.append(action.name) if failed: self.report({'WARNING'}, "Missing 'animation_end_frame' in: " + ", ".join(failed)) else: self.report({'INFO'}, "Applied to all actions") return {'FINISHED'} class VIEW3D_PT_action_tools(bpy.types.Panel): bl_label = "Manual Frame Range Setter" bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_category = "Kevin Iglesias" def draw(self, context): layout = self.layout layout.label(text="Apply Manual Frame Range:") layout.operator("actiontools.apply_current", icon="ACTION") layout.operator("actiontools.apply_all", icon="FILE_REFRESH") classes = ( ACTION_OT_apply_current, ACTION_OT_apply_all, VIEW3D_PT_action_tools, ) def register(): for cls in classes: bpy.utils.register_class(cls) def unregister(): for cls in reversed(classes): bpy.utils.unregister_class(cls) if __name__ == "__main__": register()