Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Renaming edit/pose bones breaks the drivers using them. #195

Open
abppbd opened this issue Aug 29, 2024 · 3 comments
Open

Renaming edit/pose bones breaks the drivers using them. #195

abppbd opened this issue Aug 29, 2024 · 3 comments
Labels

Comments

@abppbd
Copy link

abppbd commented Aug 29, 2024

When renaming a bone (in pose & edit mode alike), the drivers using the bone break:
The bone name is put in the path section of the driver (Single Property type)
Screenshot 2024-08-29 223245
When renaming, the bone's name is not updated in the driver making it invalid, or worst, getting unwanted values from an other bone.

I Think the excpected behaviour would be to update the bone name in the driver.

@Weisl Weisl added the bug label Sep 3, 2024
@Weisl
Copy link
Owner

Weisl commented Sep 3, 2024

This could be tricky. I need to see if and how I could solve this issue

@abppbd
Copy link
Author

abppbd commented Sep 11, 2024

How come when renaming and object the driver is updated but not when renaming a bone ? Is it because Prop is a PointerProperty & Path a StringProperty ?

Anyway, wouldn't getting a list of all drivers be enought to loop over them & update their variables' path ? Sure it might slow down a bit the renaming if there are lots of drivers, but a check box to enable driver updating for bones, lets the user decide.

When doing a renaming operation I think, to get a list of driver's variables to update, something like that should be done:

"""
Thanks to testure:
    https://blenderartists.org/t/find-all-the-drivers-in-the-file/1442126/2
"""

import bpy
from pprint import pprint

# List of "data types" where drivers can be found.
collections = [
    "scenes",
    "objects",
    "meshes",
    "materials",
    "textures",
    "speakers",
    "worlds",
    "curves",
    "armatures",
    "particles",
    "lattices",
    "shape_keys",
    "lights",
    "cameras",
    "node_groups",
    # TODO: add anything else that's missing here!
]

# To only update the needed drivers.
active_armature = bpy.context.active_object

target_list = [] # [("target_bone_name", ref_to_variable_target)]

# Loop over every data types (collections).
for col in collections:
    # Get data type (e.g. "bpy.data.objects")
    collection = eval(f"bpy.data.{col}")

    # Loop over the elements of the data type.
    for ob in collection: # ~ "for ob in bpy.data.{collection}.values():"

        # Materials that use nodes are special since they don't store drivers
        # directly on the material data itself, but on the node tree.
        if isinstance(ob, bpy.types.Material) and ob.use_nodes:
            ob = ob.node_tree

        # Skip element if there is no animation data (no drivers).
        if ob.animation_data is None:            
            continue

        # Loop over the elements' drivers.
        for driver in ob.animation_data.drivers:

            # Check if armature is used in drivers
            found_armature = False

            # Go to each driver's variables.
            for var in driver.driver.variables:

                # Go to each variable's target.
                for target in var.targets:

                    # Armature used as "primary" target,
                    # potential driver's variable's target to update.
                    if target.id == active_armature:

                        target_list.append(("Bone", target)) # TODO: Get data_path bone name.

                        # Quit Loops
                        found_armature = True
                        break
                # Armature already found in driver.
                if found_armature:
                    break

"""
Fetch driver's primary target:
    bpy.data.object[0].animation_data.drivers[0].driver.variables[0].targets[0].id

Fetch driver's data_path:
    bpy.context.active_object.animation_data.drivers[0].driver.variables[0].targets[0].data_path
"""
pprint(target_list)
print("Done.\n")

@abppbd
Copy link
Author

abppbd commented Sep 11, 2024

The second part is durring the renaming loop, changing the driver's data_path.
Maybe something like that ?

# The paring of the old name with the new ones.
names = {
    "old1" : "new1",
    "old2" : "new2",
    "old3" : "new3"
    }

# Imitation of the renaming loop.
for old_name, new_name in names.items():

    # -------------------------
    # - Renaming code & stuff -
    # -------------------------
    
    # Drivers update section:

    # If the renamed bone was used in a driver.
    if old_name in target_list:
        
        dvr_target = target_list[old_name]
        
        dvr_target.data_path.replace(f'["old_name"]', f'["new_name"]')
        # TODO: ensuers the driver doesn't break if the user gives a bad name
        # making the driver variable invalid.
        # pose.bones["pose.bones"].location[0] -> new_name["pose.bones"].location[0]

As I'm not familiar with the addons' code and dabbled only recently with blender python api, thoses snippets are just drafts, not even properly tested.

I hope this is still a good starting point and thanks for your work on this amazing addon :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants