Hi,
I am working on a script, that makes copies of bones (+ their hierarchy and constraints) and renames the copies properly. Therefore the copies are made and manipulated in EditMode.
However, if I am trying to find the newly created copies in posemode, the API will return an error that the bone is non-existent (at least in EditMode).
Here’s my code:
import bpy
import os
os.system("cls")
class MakeCopy(bpy.types.Operator):
bl_idname = "bone_copy_maker.make_copy"
bl_label = "Copy Bones"
prefix = bpy.props.StringProperty(
name="Prefix",
description="Prefix that will be attached to the names of all copied bones",
default="CP_")
layers = bpy.props.BoolVectorProperty(
name="Layers",
description="Layers that will be set active for the new bones",
size=32,
subtype='LAYER')
copyConstraints = bpy.props.BoolProperty(
name="Copy Constraints",
description="Whether the templates existing constraints should be copied or not",
default=True)
makeChildOfArmature = bpy.props.BoolProperty(
name="Make Child of Armature",
description="Should copies be children of the existing armature, if just part of it get's copied",
default=True)
addConstraints = bpy.props.BoolProperty(
name="Add Constraints",
description="Whether the old bones should have CopyTransformsConstraints to their new counterparts",
default=True)
constraintDriverName = bpy.props.StringProperty(
name="Name of new Driver",
description="Name of the new Driver for the constraints (can be empty if not needed)",
default="NewDriver")
def invoke(self, context, event):
wm = bpy.context.window_manager
return wm.invoke_props_dialog(self)
execute(self, context)
def execute(self, context):
arm = bpy.context.active_object
bones = arm.data.edit_bones
pose = arm.pose
errorMessage = ""
#check if there is a problem with the selected Prefix
prefixValid = True
if self.prefix == "" or self.prefix is None:
prefixValid = False
errorMessage = "Empty prefix! "
else:
for bone in bones:
if self.prefix == bone.name[:len(self.prefix)]:
prefixValid = False
errorMessage = "Prefix allready occurs in armature! "
layersValid = False
for layer in self.layers:
if layer == True:
layersValid = True
if not layersValid:
errorMessage += "No layer selected! "
#everything good, copy can be made
if prefixValid and layersValid:
original_bones = bpy.context.selected_editable_bones
new_bones = []
#initializing new bones
for original_bone in original_bones:
#create new bone
new_bone = arm.data.edit_bones.new(self.prefix + original_bone.name)
new_bones.append(new_bone)
#parenting new bones
for i in range(len(original_bones)):
original_bone = original_bones[i]
new_bone = new_bones[i]
original_parent = original_bone.parent
if original_parent is not None:
if original_parent in original_bones:
index = original_bones.index(original_parent)
new_bone.parent = new_bones[index]
else:
if self.makeChildOfArmature:
new_bone.parent = original_parent
#move new bones into selected layer and copy originals settings
for i in range(len(original_bones)):
original_bone = original_bones[i]
new_bone = new_bones[i]
new_bone.layers=self.layers
new_bone.use_connect = original_bone.use_connect
new_bone.head = original_bone.head
new_bone.tail = original_bone.tail
new_bone.matrix = original_bone.matrix
#here's where things get wonky
if self.copyConstraints:
pose.bones.update()
for i in range(len(original_bones)):
original_bone = original_bones[i]
new_bone = new_bones[i]
for constraint in pose.bones[original_bone.name].constraints:
#this line returns the mentioned error
copied_constraint = pose.bones[new_bone.name].constraints.new(type=constraint.type, name=constraint.name)
self.report({'INFO'}, "Successfully copied %d bones with prefix \"%s\"" %(len(original_bones), self.prefix))
return{'FINISHED'}
else:
self.report({'ERROR'}, "Copy failed: " + errorMessage)
return{'CANCELLED'}
class BoneCopyPanel(bpy.types.Panel):
bl_space_type = "VIEW_3D"
bl_region_type = "TOOLS"
bl_category = "Tools"
bl_label = "BoneCopyMaker"
@classmethod
def poll(self, context):
arm = bpy.context.active_object
return bpy.context.mode == 'EDIT_ARMATURE'
def draw(self, context):
lay = self.layout
lay.operator(MakeCopy.bl_idname)
def register():
bpy.utils.register_module(__name__)
def unregister():
bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
try:
unregister()
except Exception as e:
print(e)
pass
register()
Anyone got an idea, what I’m doing wrong?