Update in UD link does not update object in Volume Builder Object List



  • I am trying to automatically update the object list in a Volume Builder. I am using a User Data link. When I drop a new object in the UD link field, the object in the Volume Builder list does not update. Is there a way to do this? Below is the code I am using:

    import c4d
    from c4d.modules import volume
    import pprint
    from c4d import documents
    from c4d import utils
    
    
    Bake_Button = 240
    
    obj = op.GetObject()
    #obj = doc.SearchObject("Spritz 4.0")
    UD = obj.GetUserDataContainer()
    
    bottle = obj[c4d.ID_USERDATA,5]
    set_bottle = 242
    delete_bottle = 243
    
    document = op.GetDocument()
    settings = c4d.BaseContainer()
    selected = doc.GetActiveObjects(0)
    taglist = doc.GetActiveTags()
    
    presets = obj[c4d.ID_USERDATA,13]
    drop_name = obj[c4d.ID_USERDATA,197]
    
    
    
    
    def set_delete_UD_object():
    
        vol_build = doc.SearchObject("VB Drops")
        vol_build_drip_1 = doc.SearchObject("VB Drip 1")
    
        if obj[c4d.ID_USERDATA, set_bottle] == 1:
            vol_build.AddSceneObject(bottle, index = 0)
            vol_build.SetBoolMode(0, 2)
            vol_build_drip_1.AddSceneObject(bottle, index = 0)
            vol_build_drip_1.SetBoolMode(0, 2)
    
            obj[c4d.ID_USERDATA, set_bottle] = False
            for descId, container in UD: # SET Object hide
                if descId[1].id == 266:
                    container[c4d.DESC_HIDE] = True
                    obj.SetUserDataContainer(descId, container)
    
            for descId, container in UD: # DELETE Object show
                if descId[1].id == 267:
                    container[c4d.DESC_HIDE] = False
                    obj.SetUserDataContainer(descId, container)
    
    
        if obj[c4d.ID_USERDATA, delete_bottle] == 1:
                vol_build.RemoveObject(0)
                vol_build_drip_1.RemoveObject(0)
    
                obj[c4d.ID_USERDATA, delete_bottle] = False
                for descId, container in UD: # SET Object show
                    if descId[1].id == 267:
                        container[c4d.DESC_HIDE] = True
                        obj.SetUserDataContainer(descId, container)
    
                for descId, container in UD: # DELETE Object hide
                    if descId[1].id == 266:
                        container[c4d.DESC_HIDE] = False
                        obj.SetUserDataContainer(descId, container)
    
    def main():
    
        set_delete_UD_object()

  • Global Moderator

    Hi @Swinn no worries, but please make sure to use Q&A functionality 😉.

    According to your description, I made my own setup, with a Null which gets a userData link. Then I attach a python script to this Null object.
    I also created a Volume Builder called Volume Builder. Using the following code it's working as expected.

    import c4d
    from c4d.modules import volume
    
    def main():
        # Get the host object and the linked obj from the user data
        obj = op.GetObject()
        linkedObj = obj[c4d.ID_USERDATA,1]
        if not linkedObj: return
    
        # Get the volume builder
        vBuilder = doc.SearchObject("Volume Builder")
        if not vBuilder and not vBuilder.CheckType(c4d.Ovolumebuilder): return
    
        # Check if our object is not already in the list
        allowedObj = [linkedObj] # Maybe you got some other object you don't want to delete
        alreadyIn = False
        for i in xrange(0, vBuilder.GetListEntryCount()):
            o = vBuilder.GetInputObject(i)
    
            # If is not in our list of allowed objects we remove it
            if o not in allowedObj:
                vBuilder.RemoveObject(i)
            
            # If our linked object is already in the list
            if o == linkedObj:
                alreadyIn = True
            
        # Only add if the object is not already in the list
        if not alreadyIn:
            vBuilder.AddSceneObject(linkedObj)
            vBuilder.SetBoolMode(0, 2)
    

    Maybe you can try to reduce your code. Moreover, it looks like you are adding and deleting the bottle at the same time.

    Additionally, I would not recommend you to define variables in global space of the script but rather in local space of your function.

    if you have any question, please me know!
    Cheers,
    Maxime.



  • This is starting to work but it now adds 2 user data objects. As well, do I need to add an event to get a refresh? Also, I am trying to move the linked user data object to the top of the hierarchy but it doesn't want to go there. And finally, MIST Cloner and SMALL DROPS Cloner keep switching places.

    import c4d
    from c4d.modules import volume
    
    def main():
        # Get the host object and the linked obj from the user data
        obj = op.GetObject()
        linkedObj = obj[c4d.ID_USERDATA,5]
        if not linkedObj: return
    
        # Get the volume builder
        vBuilder = doc.SearchObject("VB Drops")
        if not vBuilder and not vBuilder.CheckType(c4d.Ovolumebuilder): return
    
        # Check if our object is not already in the list
        allowedObj = [linkedObj] # Maybe you got some other object you don't want to delete
        alreadyIn = False
        for i in xrange(0, vBuilder.GetListEntryCount()):
            o = vBuilder.GetInputObject(i)
    
            # If is not in our list of allowed objects we remove it
            if o not in allowedObj:
                vBuilder.RemoveObject(i)
    
            # If our linked object is already in the list
            if o == linkedObj:
                alreadyIn = True
    
        # Only add if the object is not already in the list
        if not alreadyIn:
            vBuilder.AddSceneObject(linkedObj, index = 0)
            vBuilder.SetBoolMode(0, 2)
    

    I have added index = 0 to your code but it doesn't seem to work.

    0_1539033606921_CINEMA 4DScreenSnapz008.jpg

    0_1539033625748_CINEMA 4DScreenSnapz009.jpg


  • Global Moderator

    Hi @Swinn, if you add another object through another UserData link, then you have to properly insert it, and keep track of it inside the volume builder as well and handle the "refresh" yourself as I demonstrated in my previous example.
    Since you are doing it for more than one object, in my previous example I used a variable called alreadyIn, to keep track of my object. But it was a very simple example.
    If you are switching to multiple objects, it may be worth making a data structure where you hold the objects, and if these are already inserted or not, in order to be able to track your objects properly.

    In the end this is probably more an algorithmic problem, and not that much API related. Thus we as the SDK Team can only give advice and suggest a direction.

    Moreover, in your code, I don't see any link to the new UserData link. And you are still deleting 'BIG DROPS CLONER' and all others custom cloners you have in your image. Are you sure you use the same code than the one you posted?

    Furthermore vBuilder.AddSceneObject(linkedObj, index = 0) respects the order, with index parameter set to zero linkedObj will be correctly inserted at the top of the list.

    Cheers,
    Maxime!



  • @m_adam Cool. Thank-you for your time and patience. ☺