Solved GetUserDataContainer() and UserData Values

Hi, this is about some basic undestanding...

i can get a BaseList2D UserData Container like this
udc = op.GetUserDataContainer()
which is a list of DescID / BaseContainer tuples

now... is it possible to get the actual UserData values out of this without having the BaseList2D?
or are they not stored directly in these BaseContainers?

background is that i save the udc to a HyperFile and restore/clone it back to different objects.

best, Index


I am not sure that I do follow the question. What do you mean by `without having the BaseList2D'? When you can access the description of the node, you have access to the node, so I am a bit confused. But no, the description does not store the values, they are in the data container of the node.

You can iterate over the description of a node with c4d.C4DAtom.GetDescription. GetUserDataContainer is basically just a thin wrapper around that, which skips all
non-user data elements. To access all user data of a node (of unknown count) you can do this:

import c4d

# Goes over the first 1000 user data indices.
for eid in range(1, 1001):
        print op[c4d.ID_USERDATA, eid]
    except AttributeError:
        # Will be raised when you try to access a non-existing element.


MAXON SDK Specialist

hi zipit,

ok, so GetUserDataContainer() is only the Description, I already thought so.
but what does it mean when you say about the values "they are in the data container of the node"?
I know you get the value by op[c4d.ID_USERDATA, id] but are those values stored in the bc you get by op.GetData() ?
Is there a way to get all values in a bc without iterating through the indexes?
Where does c4d.ID_USERDATA point to?

🙂 index


You can also use the function GetParameter to retrieve the value for the parameter.
Using GetParameter/SetParameter assure you to retrieve the value. Not all value are stored in the BaseContainer of the object.

def main():
    udc = op.GetUserDataContainer()
    for data in udc:
        print (op.GetParameter(data[0] ,c4d.DESCFLAGS_GET_NONE ))


MAXON SDK Specialist

MAXON Registered Developer

hm ok, I dont understand where they are stored, but it seems there is no bc on the baselist2d holding the values
i have to fetch them by using the ids in the description, add them to a new bc and then save it along with the description
(if i want a hyperfile holding the description and the values)

ok, I think I figured it out :

op[c4d.USERDATA, id] is the same as op.GetData()[c4d.USERDATA][id]

the UserData values are stored in a sub BaseContainer of op.GetData() with the id c4d.USERDATA=700

so to store all values of a BaseList2D into a HyperFile :

... EDIT:
interesting is that even though the UserData in the GUI shows 0 for a freshly added integer
op.GetData()[c4d.USERDATA] doesnt have it unless you actually have pressed enter in the input field in the GUI.
so op.GetData()[c4d.USERDATA] is NOT reliable to have all values
for a freshly added id :
op[c4d.USERDATA,17] # 0
op.GetData()[c4d.USERDATA][17] # nuthin' 😕

anyway, topic solved, i guess...
(where can you set that yourself? its not in the topic tools)


brackets are aliases to the function GetParameter, see getitem for a GeListNode
While op.GetData return a copy of the BaseContainer. (from BaseList2D)

(by the way it's c4d.ID_USERDATA that is equal to 700.

so op[c4d.ID_USERDATA, id] is NOT the same as op.GetData()[c4d.ID_USERDATA][id]

For what i see, for object, UserData are not stored in the object's BaseContainer but in some internal data.

Can you share a scene to let me understand why it's working on your case ?

about the forum:
you first need to mark this thread as "ask a question" to access the "mark as solved" or "mark this thread as then answer" option
See this thread for more information.


MAXON SDK Specialist

MAXON Registered Developer

thanks, manuel,

right, c4d.ID_USERDATA .-)
but this works here, I just verified again :

create any object, add some userdata, lets say an integer with id = 1
op[c4d.ID_USERDATA, 1] # 0
op.GetData()[c4d.ID_USERDATA][1] #
op[c4d.ID_USERDATA, 1] = 123 # 123
op.GetData()[c4d.ID_USERDATA][1] # 123 <-- you need to set the value, first (by gui or code)

op.GetData() is a BaseContainer having a sub-BaseContainer with id=700,
so i suppose this is where the values are stored, after they have been set.
if they have not been set, op[c4d.ID_USERDATA, 1] seems to return the default value from the description.

but its kind of useless, because you need to iterate the description anyway to be sure to get all values
problem there is that if you iterate the description there are also ids for groups, separators (and other stuff?)
which are not (changeable) values, so you have to filter these out.

best, index


ha, i was not setting any value. So yes, they are in the BaseContainer at id c4d.ID_USERDATA (=700)

to filter the groups or separator you just have to check the type in the descLevel and compare with DTYPE_SEPARATOR or DTYPE_GROUP or either use DescId.IsPartOf like:

    for descId, parameterBc in op.GetUserDataContainer():
        print(c4d.DESCID_DYNAMICSUB.IsPartOf(descId)) # Will print True for all of them


MAXON SDK Specialist

MAXON Registered Developer