RemoveUserData does not fully remove User Data



  • If I add a string field with AddUserData.
    And then I delete that string field with DeleteUserData.
    And then try to add a float field with AddUser Data:
    I get
    TypeError: setitem expected str, not float
    And if I try to get the value before EventAdd, I get the old, deleted value

    Anyone know any workarounds? Like how to flush the memory of the user data?



  • Here's a simple test to run in the script editor:
    Add a Cube to the scene.

    import c4d
    current_doc = c4d.documents.GetActiveDocument()  
    cube = current_doc.SearchObject('Cube')
    
    def AddStringDataType(obj):
      if obj is None: return
    
      bc = c4d.GetCustomDataTypeDefault(c4d.DTYPE_STRING) 
      bc[c4d.DESC_NAME] = "String"           
    
      element = obj.AddUserData(bc)  
      obj[element] = 'bob'       
      c4d.EventAdd()             
      
    def AddFloatDataType(obj):
      if obj is None: return
      bc = c4d.GetCustomDataTypeDefault(c4d.DTYPE_REAL)
      bc[c4d.DESC_NAME] = "Float"
      element = obj.AddUserData(bc)
      obj[element] = 22.2
      c4d.EventAdd()
      
    AddStringDataType(cube)
    cube.RemoveUserData(1)
    AddFloatDataType(cube)
    

  • Global Moderator

    Hi,

    Even if a user data parameter is removed its data is still stored. And when [] operator is used, the Python API layer checks the type of a parameter before setting its data.
    The solution is to use del() passing the parameter data to clear its type and value. Then the parameter can be set any data.

    Here is how I modified the script you posted:

    import c4d
    
    def AddUserData(obj, dtype, name):
        if obj is None: return
    
        # Retrieves default user data container for the passed type
        bc = c4d.GetCustomDataTypeDefault(dtype)
        bc[c4d.DESC_NAME] = name
    
        # Adds the user data
        element = obj.AddUserData(bc)
    
        # Returns the user data description ID
        return element
    
    def main():
        # Searches for 'Cube' object
        cube = doc.SearchObject('Cube')
        if cube is None:
            return
    
        # Adds string user data
        dataID = AddUserData(cube, c4d.DTYPE_STRING, "String")
        cube[dataID] = 'bob'
    
        # Removes user data
        cube.RemoveUserData(dataID)
        # Clears user data type and value
        del(cube[dataID])
    
        # Adds float user data
        dataID = AddUserData(cube, c4d.DTYPE_REAL, "Float")
        cube[dataID] = 22.2
    
        # Updates Cinema
        c4d.EventAdd()
    
    if __name__=='__main__':
        main()
    

    Note it's recommended to use main() like in the default script. Also when Cinema 4D runs scripts doc is the active document (op is the active object).



  • This worked. Thank you.