I figured this out. Tested on 3.5
Watch out for collection names! You need 4 collections for this transfer to work
placements - for referenced position/rotation/size
collection - where the duplicable hierarchy is, name of this one doesn’t matter
new_collection - where finalized duplicates will be located
temp_collection - only for the script to work with, but still required during the process
import bpy
source_collection_name = "source_collection"
target_collection_name = "new_collection"
temp_collection_name = "temp_collection"
# Get the source and target collections by name
source_collection = bpy.data.collections.get(source_collection_name)
target_collection = bpy.data.collections.get(target_collection_name)
temp_collection = bpy.data.collections.get(temp_collection_name)
placements = bpy.data.collections["placements"]
new_collection = bpy.data.collections["new_collection"]
temp_collection = bpy.data.collections["temp_collection"]
for obj in placements.objects:
new_hierarchy = bpy.ops.object.duplicate_move_linked(OBJECT_OT_duplicate={"linked":True, "mode":'TRANSLATION'}, TRANSFORM_OT_translate={"value":(0, 0, 0), "orient_axis_ortho":'X', "orient_type":'GLOBAL', "orient_matrix":((100, 0, 0), (0, 0, 0), (0, 0, 0)), "orient_matrix_type":'GLOBAL', "constraint_axis":(False, False, False), "mirror":False, "use_proportional_edit":False, "proportional_edit_falloff":'SMOOTH', "proportional_size":1, "use_proportional_connected":False, "use_proportional_projected":False, "snap":False, "snap_elements":{'INCREMENT'}, "use_snap_project":False, "snap_target":'CLOSEST', "use_snap_self":True, "use_snap_edit":True, "use_snap_nonedit":True, "use_snap_selectable_only":False, "use_snap_to_same_target":False, "snap_face_nearest_steps":1, "snap_point":(0, 0, 0), "snap_align":False, "snap_normal":(0, 0, 0), "gpencil_strokes":False, "cursor_transform":False, "texture_space":False, "remove_on_cancel":False, "view2d_edge_pan":False, "release_confirm":False, "use_accurate":False, "use_automerge_and_split":False})
if source_collection and target_collection:
# Loop through all objects in the source collection
for obj in source_collection.objects:
# Check if the object is selected and has no parent object
if obj.select_get():
# Remove the object from the source collection
source_collection.objects.unlink(obj)
# Add the object to the target collection
target_collection.objects.link(obj)
placements_collection = bpy.data.collections['placements'].objects
new_collision_collection = bpy.data.collections['new_collection'].objects
temp_collection = bpy.data.collections['temp_collection'].objects
print('moving to temp collection')
for obj in new_collection.objects:
if obj.parent is None:
new_collection.objects.unlink(obj)
# Add the object to the target collection
temp_collection.objects.link(obj)
print('transfer of data + return')
for obj1, obj2 in zip(placements_collection, temp_collection):
print('loop for objects ',obj1.name, obj2.name)
obj2.location = obj1.location
obj2.rotation_euler = obj1.rotation_euler
obj2.scale = obj1.scale
temp_collection.objects.unlink(obj2)
# Add the object to the target collection
new_collection.objects.link(obj2)