124 lines
4.2 KiB
Python
124 lines
4.2 KiB
Python
# SPDX-FileCopyrightText: 2025 Blender Studio Tools Authors
|
|
#
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
import bpy
|
|
from bpy.props import StringProperty, IntProperty
|
|
from bpy.types import Object
|
|
|
|
from typing import List
|
|
|
|
def report_invalid_drivers(context, objects: List[Object]):
|
|
blenlog = context.scene.blender_log
|
|
|
|
cat_leftover = 'Leftover Driver'
|
|
blenlog.clear_category(cat_leftover)
|
|
|
|
cat_invalid = 'Invalid Driver'
|
|
blenlog.clear_category(cat_invalid)
|
|
|
|
counter = 0
|
|
for obj in objects:
|
|
if obj.library or obj.override_library:
|
|
continue
|
|
if not obj.animation_data:
|
|
continue
|
|
for fcurve in obj.animation_data.drivers:
|
|
kwargs = {
|
|
'icon': 'DRIVER_TRANSFORM',
|
|
'operator': BLENLOG_OT_delete_driver.bl_idname,
|
|
'op_kwargs': {
|
|
'object_name': obj.name,
|
|
'driver_path': fcurve.data_path,
|
|
'array_index': fcurve.array_index,
|
|
},
|
|
}
|
|
try:
|
|
obj.path_resolve(fcurve.data_path)
|
|
except ValueError:
|
|
# If the RNA path of the driver fails to resolve to some value,
|
|
# that means the driver is pointing at nothing; A deleted modifier,
|
|
# constraint, bone, whatever.
|
|
blenlog.add(
|
|
description=f"Driver RNA path leads to nothing: '{fcurve.data_path}'.\nThis can happen when removing modifiers, constraints, bones, etc. that previously had drivers on them. Such driver can be safely deleted, else they will spam the console.",
|
|
name=obj.name,
|
|
category=cat_leftover,
|
|
**kwargs
|
|
)
|
|
counter += 1
|
|
continue
|
|
if not fcurve.driver.is_valid:
|
|
blenlog.add(
|
|
description=f"Invalid Driver: '{fcurve.data_path}'.\nThis can happen when a driver var target datablock is removed, an expression is invalid, etc.",
|
|
name=obj.name,
|
|
category=cat_invalid,
|
|
**kwargs
|
|
)
|
|
counter += 1
|
|
|
|
return counter
|
|
|
|
report_leftover_drivers = report_invalid_drivers
|
|
|
|
class BLENLOG_OT_report_invalid_drivers(bpy.types.Operator):
|
|
"""Report drivers that point to nothing"""
|
|
|
|
bl_idname = "blenlog.report_invalid_drivers"
|
|
bl_label = "Report Leftover Drivers"
|
|
bl_options = {'INTERNAL', 'REGISTER', 'UNDO'}
|
|
|
|
def execute(self, context):
|
|
counter = report_invalid_drivers(context, bpy.data.objects)
|
|
|
|
if counter > 0:
|
|
self.report({'WARNING'}, f"Found {counter} invalid drivers.")
|
|
else:
|
|
self.report({'INFO'}, f"No invalid drivers found.")
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class BLENLOG_OT_delete_driver(bpy.types.Operator):
|
|
"""Delete a driver on a local object"""
|
|
|
|
bl_idname = "blenlog.delete_driver"
|
|
bl_label = "Delete Driver"
|
|
bl_options = {'INTERNAL', 'REGISTER', 'UNDO'}
|
|
|
|
object_name: StringProperty()
|
|
driver_path: StringProperty()
|
|
array_index: IntProperty()
|
|
|
|
def execute(self, context):
|
|
obj = bpy.data.objects.get((self.object_name, None))
|
|
if not obj:
|
|
self.report({'INFO'}, f'Object "{self.object_name}" had already been removed.')
|
|
return {'CANCELLED'}
|
|
if not obj.animation_data or not obj.animation_data.drivers:
|
|
self.report(
|
|
{'INFO'}, f'All drivers of object "{self.object_name}" had already been removed.'
|
|
)
|
|
return {'CANCELLED'}
|
|
|
|
logs = context.scene.blender_log
|
|
|
|
driver = obj.animation_data.drivers.find(self.driver_path, index=self.array_index)
|
|
if driver:
|
|
obj.animation_data.drivers.remove(driver)
|
|
self.report({'INFO'}, f'Removed driver "{self.driver_path}" from object "{obj.name}"')
|
|
else:
|
|
self.report(
|
|
{'INFO'},
|
|
f'Driver "{self.driver_path} on object "{obj.name}" had already been removed.',
|
|
)
|
|
|
|
logs.remove(logs.active_log)
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
registry = [
|
|
BLENLOG_OT_report_invalid_drivers,
|
|
BLENLOG_OT_delete_driver,
|
|
]
|