S22: c4d.MCOMMAND_SPLIT returns a Bool instead of a List, while it returned a list in R21 and earlier versions



  • Hey guys, i have a script which uses the c4d.utils.SendModelingCommand until recently this returned a list to me. https://developers.MAXON.net/docs/Cinema4DPythonSDK/html/modules/c4d.utils/index.html#c4d.utils.SendModelingCommand

    This function either returns a boolean, or a list. Up until R21 the following code returned a list to me. But as of S22 i get returned the bool true, which signifies it ran succesfully, but i cant seem to retrieve the list.

    Any help on how i can get the list ( by passing a parameter or anything else ) would be appreciated.

    Heres the related snippet of my code

    selId = []
        sel = op.GetPolygonS()
        for index, selected in enumerate(sel.GetAll(polyCnt)):
            if not selected: continue
            selId.append(index)
        allPolys = [n for n in allPolys if n not in selId]
        settings = c4d.BaseContainer()
        res = utils.SendModelingCommand(command = c4d.MCOMMAND_SPLIT,
                                    list = [op],
                                    mode = c4d.MODELINGCOMMANDMODE_POLYGONSELECTION,
                                    bc = settings,
                                    doc = doc)
    

    after running this script, res is now true instead of a List

    many thanks in advance.



  • Thanks for the complete code, the issue is not located in the MCOMMAND_SPLIT but in the ID_MODELING_FILL_SELECTION_TOOL, within the S22 development cycle, parameters IDs changed but the new ones were not exposed to Python (I've created a bug report) so you need to hardcode them, like so

    startPolyID = c4d.MDATA_FILLSEL_START_POLY if c4d.GetC4DVersion() < 21600 else 1100 # MDATA_FILL_POLYGON_INDEX in C++
    selectionTypeID = c4d.MDATA_FILLSEL_SELECTION if c4d.GetC4DVersion() < 21600 else 1110 # MDATA_FILL_SELECTION_TYPE in C++
    

    And here your code adapted to work

    import c4d
    from c4d import gui,utils
    
    def main():
        if op.GetType() != c4d.Opolygon : return
        sel = op.GetPolygonS()
        polyCnt = op.GetPolygonCount()
        allPolys = range(polyCnt)
        doc.StartUndo()
        null = c4d.BaseObject(c4d.Onull)
        null[c4d.ID_BASELIST_NAME] = op[c4d.ID_BASELIST_NAME]+"_Segments"
        null.SetMg(op.GetMg())
        cntr = 0
        while allPolys:
            settings = c4d.BaseContainer()
            startPolyID = c4d.MDATA_FILLSEL_START_POLY if c4d.GetC4DVersion() < 21600 else 1100 # MDATA_FILL_POLYGON_INDEX in C++
            selectionTypeID = c4d.MDATA_FILLSEL_SELECTION if c4d.GetC4DVersion() < 21600 else 1110 # MDATA_FILL_SELECTION_TYPE in C++
            
            settings[startPolyID] = allPolys[0]
            settings[selectionTypeID] = c4d.SELECTION_NEW # Or SELECTION_ADD or SELECTION_SUB
    
            utils.SendModelingCommand(command = c4d.ID_MODELING_FILL_SELECTION_TOOL,
                                        list = [op],
                                        mode = c4d.MODELINGCOMMANDMODE_EDGESELECTION,
                                        bc = settings,
                                        doc = doc)
            selId = []
            sel = op.GetPolygonS()
            for index, selected in enumerate(sel.GetAll(polyCnt)):
                if not selected: continue
                selId.append(index)
                
            allPolys = [n for n in allPolys if n not in selId]
            settings = c4d.BaseContainer()
            res = utils.SendModelingCommand(command = c4d.MCOMMAND_SPLIT,
                                        list = [op],
                                        mode = c4d.MODELINGCOMMANDMODE_POLYGONSELECTION,
                                        bc = settings,
                                        doc = doc)
            
            res[0][c4d.ID_BASELIST_NAME] = op[c4d.ID_BASELIST_NAME]
            res[0].InsertUnderLast(null)
            res[0].SetMg(op.GetMg())
            sel.DeselectAll()
            cntr += 1
        doc.InsertObject(null)
        doc.AddUndo(c4d.UNDOTYPE_NEW, null)
        doc.EndUndo()
        c4d.EventAdd()
    
    
    if __name__=='__main__':
        main()
    

    Cheers,
    Maxime.



  • Hi @Awesuus first of all welcome in the plugincafe community :)

    Unfortunately, I wasn't able to reproduce your result in S22 and we correctly had a list returned.
    So what's your exact Cinema 4D Version? ( I tested on S22.118).
    Could you upload the Cinema 4D file where you are experiencing this issue?

    Thanks in advance,
    Cheers,
    Maxime.



  • Hi Maxime,
    Thank you so much for your reply. I also work in S22.118.

    Here's the whole script that I'm trying to get to work:

    import c4d
    from c4d import gui,utils
    
    def main():
        if op.GetType() != c4d.Opolygon : return
        sel = op.GetPolygonS()
        polyCnt = op.GetPolygonCount()
        allPolys = range(polyCnt)
        doc.StartUndo()
        null = c4d.BaseObject(c4d.Onull)
        null[c4d.ID_BASELIST_NAME] = op[c4d.ID_BASELIST_NAME]+"_Segments"
        null.SetMg(op.GetMg())
        cntr = 0
        while allPolys:
            settings = c4d.BaseContainer()
            settings[c4d.MDATA_FILLSEL_START_POLY] = allPolys[0]
            utils.SendModelingCommand(command = c4d.ID_MODELING_FILL_SELECTION_TOOL,
                                        list = [op],
                                        mode = c4d.MODELINGCOMMANDMODE_EDGESELECTION,
                                        bc = settings,
                                        doc = doc)
            selId = []
            sel = op.GetPolygonS()
            for index, selected in enumerate(sel.GetAll(polyCnt)):
                if not selected: continue
                selId.append(index)
            allPolys = [n for n in allPolys if n not in selId]
            settings = c4d.BaseContainer()
            res = utils.SendModelingCommand(command = c4d.MCOMMAND_SPLIT,
                                        list = [op],
                                        mode = c4d.MODELINGCOMMANDMODE_POLYGONSELECTION,
                                        bc = settings,
                                        doc = doc)
            
            res[0][c4d.ID_BASELIST_NAME] = op[c4d.ID_BASELIST_NAME]
            res[0].InsertUnderLast(null)
            res[0].SetMg(op.GetMg())
            sel.DeselectAll()
            cntr += 1
        doc.InsertObject(null)
        doc.AddUndo(c4d.UNDOTYPE_NEW, null)
        doc.EndUndo()
        c4d.EventAdd()
    
    
    if __name__=='__main__':
        main()
    

    What I'm trying to get it to do is explode the mesh by edge selection, so that it creates a new null with the separate objects. The c4d file below is just a scene with a sphere with edge selections.

    test.c4d



  • Thanks for the complete code, the issue is not located in the MCOMMAND_SPLIT but in the ID_MODELING_FILL_SELECTION_TOOL, within the S22 development cycle, parameters IDs changed but the new ones were not exposed to Python (I've created a bug report) so you need to hardcode them, like so

    startPolyID = c4d.MDATA_FILLSEL_START_POLY if c4d.GetC4DVersion() < 21600 else 1100 # MDATA_FILL_POLYGON_INDEX in C++
    selectionTypeID = c4d.MDATA_FILLSEL_SELECTION if c4d.GetC4DVersion() < 21600 else 1110 # MDATA_FILL_SELECTION_TYPE in C++
    

    And here your code adapted to work

    import c4d
    from c4d import gui,utils
    
    def main():
        if op.GetType() != c4d.Opolygon : return
        sel = op.GetPolygonS()
        polyCnt = op.GetPolygonCount()
        allPolys = range(polyCnt)
        doc.StartUndo()
        null = c4d.BaseObject(c4d.Onull)
        null[c4d.ID_BASELIST_NAME] = op[c4d.ID_BASELIST_NAME]+"_Segments"
        null.SetMg(op.GetMg())
        cntr = 0
        while allPolys:
            settings = c4d.BaseContainer()
            startPolyID = c4d.MDATA_FILLSEL_START_POLY if c4d.GetC4DVersion() < 21600 else 1100 # MDATA_FILL_POLYGON_INDEX in C++
            selectionTypeID = c4d.MDATA_FILLSEL_SELECTION if c4d.GetC4DVersion() < 21600 else 1110 # MDATA_FILL_SELECTION_TYPE in C++
            
            settings[startPolyID] = allPolys[0]
            settings[selectionTypeID] = c4d.SELECTION_NEW # Or SELECTION_ADD or SELECTION_SUB
    
            utils.SendModelingCommand(command = c4d.ID_MODELING_FILL_SELECTION_TOOL,
                                        list = [op],
                                        mode = c4d.MODELINGCOMMANDMODE_EDGESELECTION,
                                        bc = settings,
                                        doc = doc)
            selId = []
            sel = op.GetPolygonS()
            for index, selected in enumerate(sel.GetAll(polyCnt)):
                if not selected: continue
                selId.append(index)
                
            allPolys = [n for n in allPolys if n not in selId]
            settings = c4d.BaseContainer()
            res = utils.SendModelingCommand(command = c4d.MCOMMAND_SPLIT,
                                        list = [op],
                                        mode = c4d.MODELINGCOMMANDMODE_POLYGONSELECTION,
                                        bc = settings,
                                        doc = doc)
            
            res[0][c4d.ID_BASELIST_NAME] = op[c4d.ID_BASELIST_NAME]
            res[0].InsertUnderLast(null)
            res[0].SetMg(op.GetMg())
            sel.DeselectAll()
            cntr += 1
        doc.InsertObject(null)
        doc.AddUndo(c4d.UNDOTYPE_NEW, null)
        doc.EndUndo()
        c4d.EventAdd()
    
    
    if __name__=='__main__':
        main()
    

    Cheers,
    Maxime.



  • Thank you so much, this works like a charm!!!