Solved Copying Take Overrides from an object to another via Python not working properly

Hi there, I'm working on a script to transfer (or copy) the overrides from a source object to a target one and it seems to be working if there is no overrides in sub-Takes.
Basically what the script does is a scan through all Takes starting from the first after the Main (takeData.GetMainTake().GetDown()) and retrieves each override ID and value and it adds to the target object via FindOrAddOverrideParam().
But for any odd reason the result is not consistent if there are sub-Takes involved as it changes depending on which one is active before running the script, and in all cases, I would expect a perfect copy but that's not what's happening. I must be missing something here :/
My gut feeling says that the problem is related to the backup so I just tried forcing it via FindOverrideCounterPart() but without success.

02a090bd-ef4a-420d-8114-2457f031e39d-image.png
6cca585d-2e1a-442f-acff-3d0a46ba829a-image.png
ed31f56c-a080-4f74-b66d-d4aabfbc950d-image.png
3e4da7b3-cd3d-483f-99dd-d1f4b7913664-image.png
844555aa-6146-47ba-89f2-abd4b37c326c-image.png
9c284837-6deb-43ad-8d7b-3ac280597831-image.png
740b2c65-d301-47e2-91c1-e87a97735910-image.png

I'm sending a dummy file attached with a set of Takes just to show the problem I'm trying to describe here:

copy_overrides_to_another_object.c4d

This is the script that works with the file above:

import c4d

def GetNextTake(op):
    if op == None: return None
    if op.GetDown(): return op.GetDown()
    while not op.GetNext() and op.GetUp(): op = op.GetUp()
    return op.GetNext()

def getDescIdName(op, descID):
    description = op.GetDescription(c4d.DESCFLAGS_DESC_0)
    for bc, paramid, groupid in description:
        if paramid == descID:
            return bc[c4d.DESC_NAME]

def TransferTakeOverrides(srcObj, trgObj, takeData, currentTake):
    while currentTake:
        srcOverride = currentTake.FindOverride(takeData, srcObj)
        if srcOverride is not None:
            for descID in srcOverride.GetAllOverrideDescID():

                # Get the backup node for the source override
                backup, result = takeData.FindOverrideCounterPart(srcOverride, descID) # backup: The counterpart node // result: the Take

                if backup is None:
                    raise RuntimeError("Failed to find the default override.")

                # Get the backup value of the given Description ID
                backupValue = backup.GetParameter(descID, c4d.DESCFLAGS_GET_0)

                print(currentTake.GetName(), "      DescID:", getDescIdName(srcObj,descID))
                print(" --->",srcOverride.GetSceneNode().GetName())
                print("        overr. value:", srcOverride.GetParameter(descID, c4d.DESCFLAGS_GET_0))
                print("        backup value:", backupValue,"from", result.GetName())

                # Get the override value
                srcOverValue = srcOverride.GetParameter(descID, c4d.DESCFLAGS_GET_0)
                # add override to the target object
                trgOverride = currentTake.FindOrAddOverrideParam(takeData, trgObj, descID, srcOverValue)

                # Get the backup node for the target override
                trg_backup, trg_result = takeData.FindOverrideCounterPart(trgOverride, descID)
                trg_backupValue = trg_backup.GetParameter(descID, c4d.DESCFLAGS_GET_0)

                # force adding source backup value to the target backup take (just trying to fix the problem!)
                trgBackup = trg_result.FindOrAddOverrideParam(takeData, trgObj, descID, backupValue)
                trgBackup.UpdateSceneNode(takeData, descID)

                trgOverride.UpdateSceneNode(takeData, descID)

                print(" --->",trgOverride.GetSceneNode().GetName())
                print("        overr. value:", trgOverride.GetParameter(descID, c4d.DESCFLAGS_GET_0))
                print("        backup value:", trg_backupValue,"from", trg_result.GetName())
                print("        ----------------")

            currentTake = GetNextTake(currentTake)
            print("======================================")

def main():
    op = c4d.BaseObject(c4d.Ocube)
    op[c4d.ID_BASELIST_NAME] = "trg_Cube"
    doc.InsertObject(op)
    objs = doc.GetObjects()
    objs.reverse()

    if len(objs) != 2: return

    takeData = doc.GetTakeData()
    currentTake = takeData.GetMainTake().GetDown()

    TransferTakeOverrides(srcObj=objs[0], trgObj=objs[1], takeData=takeData, currentTake=currentTake)

    c4d.EventAdd()

if __name__=='__main__':
    main()

Hi,

Finally found why by adding the backupvalue in the function FindOrAddOverrideParam.
I yet, need to understand why because it should be optional even if this parameter is there for something.
Maybe for one of those case but I am not sure.

import c4d

def GetNextTake(op):
    if op == None: return None
    if op.GetDown(): return op.GetDown()
    while not op.GetNext() and op.GetUp(): op = op.GetUp()
    return op.GetNext()

def getDescIdName(op, descID):
    description = op.GetDescription(c4d.DESCFLAGS_DESC_0)
    for bc, paramid, groupid in description:
        if paramid == descID:
            return bc[c4d.DESC_NAME]

def TransferTakeOverrides(srcObj, trgObj, takeData, currentTake):
    while currentTake:
        srcOverride = currentTake.FindOverride(takeData, srcObj)
        if srcOverride is not None:
            for descID in srcOverride.GetAllOverrideDescID():

                # Get the backup node for the source override
                backup, ownerTake = takeData.FindOverrideCounterPart(srcOverride, descID) # backup: The counterpart node // result: the Take

                if backup is None:
                    raise RuntimeError("Failed to find the default override.")

                # Get the backup value of the given Description ID
                backupValue = backup.GetParameter(descID, c4d.DESCFLAGS_GET_0)
                srcOverValue = srcOverride.GetParameter(descID, c4d.DESCFLAGS_GET_0)

                print(currentTake.GetName(), "      DescID:", getDescIdName(srcObj,descID))
                print(" --->",srcOverride.GetSceneNode().GetName())
                print("        overr. value:", srcOverValue)
                print("        backup value:", backupValue,"from", ownerTake.GetName())

                # Get the override value
               
                # add override to the target object
                trgOverride = currentTake.FindOrAddOverrideParam(takeData, trgObj, descID, srcOverValue, backupValue)
                trgOverride.UpdateSceneNode(takeData, descID)


                # Get the backup node for the target override
                trg_backup, trg_ownerTake = takeData.FindOverrideCounterPart(trgOverride, descID)
                trgOverValue = trgOverride.GetParameter(descID, c4d.DESCFLAGS_GET_0)
                trg_backupValue = trg_backup.GetParameter(descID, c4d.DESCFLAGS_GET_0)
                

                print(" --->",trgOverride.GetSceneNode().GetName())
                print("        overr. value:", trgOverValue)
                print("        backup value:", trg_backupValue,"from", trg_ownerTake.GetName())
                print("        ----------------")

            currentTake = GetNextTake(currentTake)
            print("======================================")

def main():
    op = c4d.BaseObject(c4d.Ocube)
    op[c4d.ID_BASELIST_NAME] = "trg_Cube"
    doc.InsertObject(op)
    objs = doc.GetObjects()
    objs.reverse()

    if len(objs) != 2: return

    takeData = doc.GetTakeData()
    currentTake = takeData.GetMainTake().GetDown()

    TransferTakeOverrides(srcObj=objs[0], trgObj=objs[1], takeData=takeData, currentTake=currentTake)

    c4d.EventAdd()

if __name__=='__main__':
    main()

Cheers,
Manuel

MAXON SDK Specialist

MAXON Registered Developer

Hi,

Finally found why by adding the backupvalue in the function FindOrAddOverrideParam.
I yet, need to understand why because it should be optional even if this parameter is there for something.
Maybe for one of those case but I am not sure.

import c4d

def GetNextTake(op):
    if op == None: return None
    if op.GetDown(): return op.GetDown()
    while not op.GetNext() and op.GetUp(): op = op.GetUp()
    return op.GetNext()

def getDescIdName(op, descID):
    description = op.GetDescription(c4d.DESCFLAGS_DESC_0)
    for bc, paramid, groupid in description:
        if paramid == descID:
            return bc[c4d.DESC_NAME]

def TransferTakeOverrides(srcObj, trgObj, takeData, currentTake):
    while currentTake:
        srcOverride = currentTake.FindOverride(takeData, srcObj)
        if srcOverride is not None:
            for descID in srcOverride.GetAllOverrideDescID():

                # Get the backup node for the source override
                backup, ownerTake = takeData.FindOverrideCounterPart(srcOverride, descID) # backup: The counterpart node // result: the Take

                if backup is None:
                    raise RuntimeError("Failed to find the default override.")

                # Get the backup value of the given Description ID
                backupValue = backup.GetParameter(descID, c4d.DESCFLAGS_GET_0)
                srcOverValue = srcOverride.GetParameter(descID, c4d.DESCFLAGS_GET_0)

                print(currentTake.GetName(), "      DescID:", getDescIdName(srcObj,descID))
                print(" --->",srcOverride.GetSceneNode().GetName())
                print("        overr. value:", srcOverValue)
                print("        backup value:", backupValue,"from", ownerTake.GetName())

                # Get the override value
               
                # add override to the target object
                trgOverride = currentTake.FindOrAddOverrideParam(takeData, trgObj, descID, srcOverValue, backupValue)
                trgOverride.UpdateSceneNode(takeData, descID)


                # Get the backup node for the target override
                trg_backup, trg_ownerTake = takeData.FindOverrideCounterPart(trgOverride, descID)
                trgOverValue = trgOverride.GetParameter(descID, c4d.DESCFLAGS_GET_0)
                trg_backupValue = trg_backup.GetParameter(descID, c4d.DESCFLAGS_GET_0)
                

                print(" --->",trgOverride.GetSceneNode().GetName())
                print("        overr. value:", trgOverValue)
                print("        backup value:", trg_backupValue,"from", trg_ownerTake.GetName())
                print("        ----------------")

            currentTake = GetNextTake(currentTake)
            print("======================================")

def main():
    op = c4d.BaseObject(c4d.Ocube)
    op[c4d.ID_BASELIST_NAME] = "trg_Cube"
    doc.InsertObject(op)
    objs = doc.GetObjects()
    objs.reverse()

    if len(objs) != 2: return

    takeData = doc.GetTakeData()
    currentTake = takeData.GetMainTake().GetDown()

    TransferTakeOverrides(srcObj=objs[0], trgObj=objs[1], takeData=takeData, currentTake=currentTake)

    c4d.EventAdd()

if __name__=='__main__':
    main()

Cheers,
Manuel

MAXON SDK Specialist

MAXON Registered Developer

@m_magalhaes said in Copying Take Overrides from an object to another via Python not working properly:

adding the backupvalue

You are master!
thanks my friend, it's working!