Change UserData ID#?

  • On 27/02/2013 at 13:14, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:   13 
    Platform:   Windows  ;   
    Language(s) :     C++  ;


    I'm adding and deleting UserData items in my plugin. But the way the ID#s stay local to each UD item. That is throwing everything out of sync when I delete them.
    In order to keep everything in sync in my plugin. I need to force the UserData items ID#s to always be in numerical order as they exist in the stack.

    How do we change the DescLevel() values of UserData items?

        BaseObject *obj = doc->GetActiveObject();    
      DynamicDescription *ud = obj->GetDynamicDescription();  
      DescID udEntry(DescLevel(ID_USERDATA, DTYPE_SUBCONTAINER, 0), DescLevel(3));  //<----I want to change this value from 3 to 2

    What's the deal with GetDepth()?
    Instead of returning the stack position of each UD item. It gets stuck at 2. 😠

        DescID dscID;  
      const BaseContainer *bc;  
      void *dscHnd = ud->BrowseInit();                        //Initialize the Browse function  
      counter = 1;  
      while(ud->BrowseGetNext(dscHnd, &dscID, &bc))           //Loop through the UserData entries  
          DescID udEntry(DescLevel(ID_USERDATA, DTYPE_SUBCONTAINER, 0), DescLevel(counter));  
          LONG level = udEntry.GetDepth();  
      GePrint(LongToString(level));     <---- Prints 1, 2, 2, 2, 2, etc...  
          counter ++;  


  • On 27/02/2013 at 13:17, xxxxxxxx wrote:

    Not sure about ID numbering, but GetDepth() probably isn't getting what you think.  It is getting the number of levels of a DescID (subids, basically).

  • On 28/02/2013 at 12:52, xxxxxxxx wrote:

    Can we do this?
    Is there no SDK function to change the UD's position on the stack?

    If not.
    I figured out a possible way to maybe work around it by copying the user data entry. Then deleting the original.
    But this is an awful lot of work to do. Just to change a UD's levelID#.
    I.E. Change the UD position on the stack:

       //Get the object or tag the UserData is on  
      //Then get the master UserData container  
      BaseObject *obj = doc->GetActiveObject();    
      DynamicDescription *ud = obj->GetDynamicDescription();            //The master UD container  
      //Get the specific UD we want to copy  
      DescID udSource(DescLevel(ID_USERDATA, DTYPE_SUBCONTAINER, 0), DescLevel(3)); //The UD entry to copy  
      const BaseContainer *sourceBC = ud->Find(udSource);  
      GeData d;  
      obj->GetParameter(udSource, d, DESCFLAGS_GET_0);                  //Get the values for the gizmos in the source UD we want to copy and store them in d  
      String name = sourceBC->GetString(DESC_NAME);                     //Get the name of the source UD we want to copy  
      LONG type = sourceBC->GetLong(DESC_CUSTOMGUI);                    //Get the data type setting   
      LONG unit = sourceBC->GetLong(DESC_UNIT);                         //Get the units setting(Real, Percent. etc..)  
      LONG min = sourceBC->GetLong(DESC_MIN);                           //Get the min value  
      LONG max = sourceBC->GetLong(DESC_MAX);                           //Get the max value  
      GePrint(LongToString(max));              //<--always returns Zero!?  
      //Now we create a brand new UserData from scratch  
      //The copy the data from the source to the copy...Then delete the source  
      BaseContainer CopyBC;  
      DescID udCopy(DescLevel(ID_USERDATA, DTYPE_SUBCONTAINER, 0), DescLevel(2));    //The new ID level where the copy will end up  
      udCopy = ud->Alloc(CopyBC);                                                    //Create the new UD object in memory only  
      ud->FillDefaultContainer(CopyBC, type, name);                                  //Fill the UD with some basic information and use the source's name and data type  
      CopyBC.SetLong(DESC_UNIT, unit);                                               //Set the units value using the source's units value in memory only  
      CopyBC.SetLong(DESC_MIN, min);                                                 //Set the min value using the source's units value in memory only  
      CopyBC.SetLong(DESC_MAX, max);                                                 //Set the max value using the source's units value in memory only  
      ud->Set(udCopy, CopyBC, obj);                                                  //Execute the changes made to the UD from memory  
      obj->SetParameter(DescID(udCopy), GeData(d), DESCFLAGS_SET_0);                 //Copy the gizmo values from the source UD and copy them to this new UD  
      ud->Remove(DescID(DescLevel(ID_USERDATA),DescLevel(3)));                       //Delete the original(source) UserData entry  
      SendCoreMessage(COREMSG_CINEMA, BaseContainer(COREMSG_CINEMA_FORCE_AM_UPDATE));//Update the object the UD is on to reflect the deletion(mandatory when deleting UD)  
      if(obj->IsDirty(DIRTYFLAGS_DATA)) GePrint("Changed");                         //Sends a message that the UD was changed

    One small problem though. DESC_MIN & DESC_MAX are not working properly.
    I can't copy these values and set them in the new copy UD.
    How are we supposed to use these?


  • On 01/03/2013 at 01:04, xxxxxxxx wrote:


    Here's how you can simply change the ID of a user data:

    BaseObject *op = doc->GetActiveObject();
    if (op==NULL) return FALSE;
    DynamicDescription *dynDesc = op->GetDynamicDescription();
    if (dynDesc==NULL) return FALSE;
    DescID udEntry(DescLevel(ID_USERDATA, DTYPE_SUBCONTAINER, 0), 1);
    const BaseContainer *data = dynDesc->Find(udEntry);
    if (data!=NULL)
        BaseContainer bc = *data->GetClone(COPYFLAGS_0, NULL);
        // Get the ID sub-level and increment it
        DescLevel level = udEntry[1];;
        dynDesc->Set(udEntry, bc, NULL);

  • On 01/03/2013 at 07:24, xxxxxxxx wrote:

    Thank you sir. 🍺

    I was also having trouble figuring out how to use PopId() & PushId(). And your example answered my questions about them too.


  • On 01/03/2013 at 13:27, xxxxxxxx wrote:

    Uh Oh.
    I take it back. That code doesn't work properly.

    While it does change the level. It also deletes the current values in the fields. 😠


  • On 01/03/2013 at 14:03, xxxxxxxx wrote:

    Since the code Yannick posted wacks any previous UD values.
    Here is an example that uses a combination of his code and mine. Which won't delete the UserData values when changing the level value:

    //This example creates a copy of a specific UserData entry (ID#1) with a different ID# (ID#2) (DescLevel)  
    //Then deletes the original UD entry (optional)  
    //This version also copies the values from the old UD to the new UD  
      BaseObject *op = doc->GetActiveObject();  
      if (op==NULL) return FALSE;  
      DynamicDescription *dynDesc = op->GetDynamicDescription();           //The master UD container  
      if (dynDesc==NULL) return FALSE;  
      DescID udEntry(DescLevel(ID_USERDATA, DTYPE_SUBCONTAINER, 0), 1);    //The ID is #1...The first UD item on the stack  
      const BaseContainer *data = dynDesc->Find(udEntry);                  //Get the data for this specific UD item  
      if (data!=NULL)  
          BaseContainer bc = *data->GetClone(COPYFLAGS_0, NULL);           //Get a copy of the UD's BaseContainer  
          GeData d;  
          op->GetParameter(udEntry, d, DESCFLAGS_GET_0);                   //Get the values for the gizmos in the source UD we want to copy and store them in d  
          String name = data->GetString(DESC_NAME);                        //Get the name of the source UD we want to copy  
          LONG type = data->GetLong(DESC_CUSTOMGUI);                       //Get the data type setting   
          LONG unit = data->GetLong(DESC_UNIT);                            //Get the units setting(Real, Percent. etc..)  
          dynDesc->Remove(udEntry);                                        //Delete the UD entry (Note: The UD's level is still there on the stack)   
                                                                           //We have to handle the UD's level data(DescLevel) too  
          //Get the ID sub-level and increment it  
          DescLevel level = udEntry[1];                                    //Gets the level of the UD item and assigns it to a variable  
;                                                      //Change the level to some other number  
          udEntry.PopId();                                                 //Remove the UD's level data from the stack  
          udEntry.PushId(level);                                           //Add the UD's new level data to the stack (this is what changes the ID#)  
          dynDesc->Set(udEntry, bc, NULL);                                 //Execute all these changes made to the UD from memory  
          op->SetParameter(DescID(udEntry), GeData(d), DESCFLAGS_SET_0);   //Paste the gizmo values from the original UD to this new version of the UD  


  • On 04/03/2013 at 01:26, xxxxxxxx wrote:

    Thanks for sharing your code with the complete solution.

Log in to reply