Undo loading and replacing materials

On 16/06/2017 at 03:05, xxxxxxxx wrote:

import c4d
  
def main() :
  
    File=r"d:	est\Mats.c4d"
  
    TempDoc = c4d.documents.LoadDocument(File, c4d.SCENEFILTER_MATERIALS)
    MatListTemp = list()
    MatTemp = TempDoc.GetFirstMaterial()
    while(MatTemp) :
        nMatTemp = MatTemp.GetNext()
        MatListTemp.append(MatTemp)
        MatTemp = nMatTemp
    TempDoc.Remove()
  
    MatCurentDoc = doc.GetFirstMaterial()
    MatList = list()
    while(MatCurentDoc) :
        nMatCurentDoc = MatCurentDoc.GetNext()
        MatList.append(MatCurentDoc)
        MatCurentDoc = nMatCurentDoc
  
  
    doc.StartUndo()
  
    for Mat in MatList:
        for MatTemp in MatListTemp:
            if MatTemp.GetName() == Mat.GetName() :
                LayerMat = Mat.GetLayerObject(doc)
                ObjLink = Mat[c4d.ID_MATERIALASSIGNMENTS]
  
                list_tags = list()
                for i in xrange(ObjLink.GetObjectCount()) :
                    list_tags.append(ObjLink.ObjectFromIndex(doc, i))
  
                doc.AddUndo(c4d.UNDOTYPE_CHANGE, Mat)
  
                Mat.Remove()
                doc.AddUndo(c4d.UNDOTYPE_DELETE, Mat)
  
                doc.InsertMaterial(MatTemp)
                doc.AddUndo(c4d.UNDOTYPE_NEW, MatTemp)
  
                doc.AddUndo(c4d.UNDOTYPE_CHANGE, MatTemp)
                MatTemp.SetLayerObject(LayerMat)
  
                for tag in list_tags:
                    doc.AddUndo(c4d.UNDOTYPE_CHANGE, tag)
                    tag[c4d.TEXTURETAG_MATERIAL] = MatTemp
  
    doc.EndUndo()
    c4d.EventAdd()
  
if __name__ == '__main__':
    main()

I'm downloading and replacing the materials with a script. All assigned objects are visible in the material assignments. If you undo the action (Ctrl + Z), the objects are missing in the material assignments.

On 16/06/2017 at 04:03, xxxxxxxx wrote:

Yo do undo in the wrong under. Take the Add Undo command as Save Current State.

So logically

                doc.AddUndo(c4d.UNDOTYPE_CHANGE, Mat)
  
                doc.AddUndo(c4d.UNDOTYPE_DELETE, Mat)
                Mat.Remove()
  
                doc.AddUndo(c4d.UNDOTYPE_NEW, MatTemp) #Since MatTemp already exist in memory
                doc.InsertMaterial(MatTemp)
  
                doc.AddUndo(c4d.UNDOTYPE_CHANGE, MatTemp)
                MatTemp.SetLayerObject(LayerMat)
  
                for tag in list_tags:
                    doc.AddUndo(c4d.UNDOTYPE_CHANGE, tag)
                    tag[c4d.TEXTURETAG_MATERIAL] = MatTemp

On 16/06/2017 at 04:34, xxxxxxxx wrote:

Actually, UNDOTYPE_NEW needs to be called after  the insertion. 🙂

https://developers.maxon.net/docs/Cinema4DPythonSDK/html/modules/c4d.documents/BaseDocument/index.html?highlight=addundo#BaseDocument.AddUndo

Cheers

On 16/06/2017 at 04:41, xxxxxxxx wrote:

UNDOTYPE_NEW New object/node/tag etc. was created. (Needs to be called AFTER action.)

_<_t_>_

The result is similar, after undo(ctrl+z) in "Material editor: Assignment" empty.

On 16/06/2017 at 04:52, xxxxxxxx wrote:

If you save and reopen the project, then everything will be fine

On 19/06/2017 at 08:38, xxxxxxxx wrote:

Hi,

I think both Niklas and gr4phos are basically right, it has to do with the order of AddUndo() and action.
Just to avoid confusion, in the original script posted doc.AddUndo(c4d.UNDOTYPE_DELETE, Mat) was wrongly called after Remove(), UNDOTYPE_DELETE has to be done before the action (correctly pointed out by gr4ph0s). Then gr4ph0s probably got confused himself and mixed up the order of  UNDOTYPE_NEW in his script, which has to be done after the action (as correctly pointed out by Niklas).
Getting both of these right, should fix the issue.

On 19/06/2017 at 21:28, xxxxxxxx wrote:

Alas it does not work

screencast

On 20/06/2017 at 02:57, xxxxxxxx wrote:

Hi,

please forgive me for not taking a closer look first. The AddUndo() order seemed like an obvious bug and explained the issues pretty well.
The actual issue is, that you are removing the old material too early from the document. So when the material assignment gets changed and the undo step is added, the document already has no more reference to the old material.

Here's the fixed script, with a few other notes:

import c4d
  
def main() :
  
    File = "<some path>/Mats.c4d"
  
    TempDoc = c4d.documents.LoadDocument(File, c4d.SCENEFILTER_MATERIALS)
    MatListTemp = list()
    MatTemp = TempDoc.GetFirstMaterial()
    while(MatTemp) :
        MatListTemp.append(MatTemp.GetClone()) # use clone here, later on you don't want to insert a material already inserted in another doc
        MatTemp = MatTemp.GetNext()
    TempDoc.Remove()
  
    MatCurentDoc = doc.GetFirstMaterial()
    MatList = list()
    while(MatCurentDoc) :
        MatList.append(MatCurentDoc)
        MatCurentDoc = MatCurentDoc.GetNext()
  
    doc.StartUndo()
  
    for Mat in MatList:
        for MatTemp in MatListTemp:
            if MatTemp.GetName() == Mat.GetName() :
                LayerMat = Mat.GetLayerObject(doc)
                ObjLink = Mat[c4d.ID_MATERIALASSIGNMENTS]
  
                list_tags = list()
                for i in xrange(ObjLink.GetObjectCount()) :
                    print ObjLink.ObjectFromIndex(doc, i)
                    list_tags.append(ObjLink.ObjectFromIndex(doc, i))
  
                #doc.AddUndo(c4d.UNDOTYPE_CHANGE, Mat) # redundant
  
                # moved to the end
                #Mat.Remove()
                #doc.AddUndo(c4d.UNDOTYPE_DELETE, Mat)
  
                doc.InsertMaterial(MatTemp)
                doc.AddUndo(c4d.UNDOTYPE_NEW, MatTemp)
  
                doc.AddUndo(c4d.UNDOTYPE_CHANGE, MatTemp)
                MatTemp.SetLayerObject(LayerMat)
  
                for tag in list_tags:
                    doc.AddUndo(c4d.UNDOTYPE_CHANGE, tag)
                    tag[c4d.TEXTURETAG_MATERIAL] = MatTemp
  
                doc.AddUndo(c4d.UNDOTYPE_DELETE, Mat)  # swapped, AddUndo(DELETE) before Remove()
                Mat.Remove()
                #doc.AddUndo(c4d.UNDOTYPE_DELETE, Mat)
  
    doc.EndUndo()
    c4d.EventAdd()
  
if __name__ == '__main__':
    main()

On 20/06/2017 at 03:19, xxxxxxxx wrote:

thank you, things work. 👍