Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Writing data to the .c4d file

    Cinema 4D SDK
    r20 python
    4
    26
    15.8k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • ferdinandF
      ferdinand
      last edited by ferdinand

      Hi,

      for cid, value in doc.GetDocumentData(MyUniqueId):
            print cid, value
      

      and

      doc.SetDocumentData(MyUniqueId, subBc)
      

      instead of

      bc.SetContainer(MyUniqueId, subBc)
      

      i.e.: Your misconception is that you can get/set all document data in one container. You can't (with this method). You only write/read one settings container at a time. In this case the container you did register.

      Cheers
      zipit

      MAXON SDK Specialist
      developers.maxon.net

      ? 1 Reply Last reply Reply Quote 1
      • ?
        A Former User @ferdinand
        last edited by A Former User

        @zipit Thank you so much for your patience. I changed what you said and

        doc.GetDocumentData(MyUniqueId)
        

        does print a BaseContainer, but this doesn't print anything:

        for cid, value in doc.GetDocumentData(MyUniqueId):
              print cid, value
        

        Updated script:

        import c4d
        
        PLUGIN_ID = 1234567
        MyUniqueId = 1000001
        
        def main():
            doc = c4d.documents.GetActiveDocument()
            #get the document's BaseContainer
            bc = doc.GetDataInstance()
            
            #create a sub-BaseContainer
            subBc = c4d.BaseContainer()
            subBc[1000] = "hello"
            subBc[2000] = "world!"
            
            #add the sub-BaseContainer to the document Base Container
            doc.SetDocumentData(MyUniqueId, subBc)
            
            #set the Document Data using the plugin ID
            doc.SetDocumentData(PLUGIN_ID, bc)
            c4d.EventAdd()
            
            print doc.GetDocumentData(MyUniqueId)
            # <c4d.BaseContainer object at 0x0000018F956DC1B0>
        
            #get the sub container's data
            for cid, value in doc.GetDocumentData(MyUniqueId):
                print cid, value
               
        if __name__=='__main__':
           main()
        
        1 Reply Last reply Reply Quote 0
        • ?
          A Former User
          last edited by A Former User

          I'm confused in this example how the SubBaseContainer is being added to the BaseContainer. It seems like they're both being added to the Document.

          I might be mistaken, but this was how I envisioned the data structure:

          Document ⮧
             BaseContainer Data (ID = PLUGIN_ID) ⮧
                SubBaseContainer Data (ID = MyUniqueId)
          
          ferdinandF 1 Reply Last reply Reply Quote 0
          • ferdinandF
            ferdinand
            last edited by ferdinand

            Hi,

            as I said, you can't set the whole container. Or in other words you don't need the variable bc in your example. Here is one one example that shows you how to store hierarchical data and then retrieve it. I wrote this on my iPad, so there might be bugs/typos, but the concept should be clear.

            # Your settings container
            bc = c4d.BaseContainer()
            # One level of your container, we treat this like a list/folder
            folder = c4d.BaseContainer()
            # One item in your folder
            recipe_1 = c4d.BaseContainer()
            # Another item in your folder
            recipe_2 = c4d.BaseContainer()
            
            bc[ID_TITLE] = 'My Cooking recipes'
            bc[ID_DATA] = folder
            folder[1000] = recipe_1
            folder[1001] = recipe_2
            
            recipe_1[ID_TITLE] = 'Choclate delight'
            recipe_1[ID_INSTRUCTIONS] = 'Lorem Ipsum ...'
            recipe_2[ID_TITLE] = 'Cheesekake'
            recipe_2[ID_INSTRUCTIONS] = 'Lorem Ipsum ...'
              
            doc.SetDocumentData(ID_MY_SECRET_COOKING_RECIPES, bc)
            
            def print_container(bc):
                '''
                '''
                for cid, value in bc:
                    print cid, value
                    if isinstance(value, c4d.BaseContainer):
                        print_container(value)
            
            print_container(doc.GetDocumentData(ID_MY_SECRET_COOKING_RECIPES))
            

            MAXON SDK Specialist
            developers.maxon.net

            1 Reply Last reply Reply Quote 1
            • ferdinandF
              ferdinand @A Former User
              last edited by

              @blastframe said in Writing data to the .c4d file:

              I'm confused in this example how the SubBaseContainer is being added to the BaseContainer. It seems like they're both being added to the Document.

              I might be mistaken, but this was how I envisioned the data structure:

              Document ⮧
                 BaseContainer Data (ID = PLUGIN_ID) ⮧
                    SubBaseContainer Data (ID = MyUniqueId)
              

              Hi,

              no, it is

              Document
              --- Stuff
              --- Other Stuff
              --- Your ID stuff
              --- Some clown is saving his cooking recipes here
              

              Cheers
              zipit

              MAXON SDK Specialist
              developers.maxon.net

              ? 1 Reply Last reply Reply Quote 1
              • ?
                A Former User @ferdinand
                last edited by A Former User

                @zipit Thanks for the explanation of the data structure (and the code for clarity).

                I tried my best to get it working, but it's still not printing the data. I'm not sure if it was intentional, but I changed the line

                print_container(doc.SetDocumentData(ID_MY_SECRET_COOKING_RECIPES))
                

                as it was throwing an error for not passing a BaseContainer. Did you mean?

                print_container(doc.GetDocumentData(ID_MY_SECRET_COOKING_RECIPES))
                

                Regardless it's the same issue where it does see the BaseContainer in the print function, but cannot iterate through it.

                import c4d
                
                ID_MY_SECRET_COOKING_RECIPES = 2999999
                ID_TITLE = 1008
                ID_DATA = 1009
                ID_INSTRUCTIONS = 1010
                
                def print_container(bc):
                    for cid, value in bc:
                        print cid, value
                        if isinstance(value, c4d.BaseContainer):
                            print_container(value)
                
                def main():
                    doc = c4d.documents.GetActiveDocument()
                
                    # Your settings container
                    bc = c4d.BaseContainer()
                    # One level of your container, we treat this like a list/folder
                    folder = c4d.BaseContainer()
                    # One item in your folder
                    recipe_1 = c4d.BaseContainer()
                    # Another item in your folder
                    recipe_2 = c4d.BaseContainer()
                    
                    bc[ID_TITLE] = 'My Cooking recipes'
                    bc[ID_DATA] = folder
                    folder[1000] = recipe_1
                    folder[1001] = recipe_2
                    
                    recipe_1[ID_TITLE] = 'Choclate delight'
                    recipe_1[ID_INSTRUCTIONS] = 'Lorem Ipsum ...'
                    recipe_2[ID_TITLE] = 'Cheesekake'
                    recipe_2[ID_INSTRUCTIONS] = 'Lorem Ipsum ...'
                      
                    doc.SetDocumentData(ID_MY_SECRET_COOKING_RECIPES, bc)
                
                    print_container(doc.GetDocumentData(ID_MY_SECRET_COOKING_RECIPES))
                
                if __name__=='__main__':
                   main()
                
                1 Reply Last reply Reply Quote 0
                • ?
                  A Former User
                  last edited by

                  Not sure if this matters, but my ultimate goal would be to save JSON data in the BaseContainer.

                  1 Reply Last reply Reply Quote 0
                  • ManuelM
                    Manuel
                    last edited by Manuel

                    Hello,

                    The function SetDocumentData can only be used to update the document settings.

                    It does accept an Int as a "type" but if you put something else than DOCUMENTSETTINGS_GENERAL DOCUMENTSETTINGS_MODELING DOCUMENTSETTINGS_DOCUMENT DOCUMENTSETTINGS_ANIMATIONSYSTEM the function will simply do nothing. (and the last one is marked as private)

                    BaseContainer is a tree system, you can see sub-BaseContainer just like a child object in the object manager.
                    So you can have (infinite ?) BaseContainer inside BaseContainer.

                    If you want to store json data, it's up to you. You can store all elements of your json data or simply store a string.

                    import c4d
                    
                    PLUGIN_ID = 1234567
                    MyUniqueId = 456789
                    
                    def main():
                        #retrieves the document baseContainer
                        docBC = doc.GetDataInstance()
                    
                        #create a sub-BaseContainer
                        subBc = c4d.BaseContainer()
                        subBc[1000] = "hello"
                        subBc[2000] = "world!"
                    
                        # Add the container to the "main" Container
                        docBC.SetContainer(MyUniqueId, subBc)
                    
                        # Updates the document container
                        doc.SetData(docBC)
                    
                        # Print the values stored in our container.
                        for cid, value in doc.GetDataInstance().GetContainer(MyUniqueId):
                            print cid, value
                        
                        # Print Hello World
                        print doc[MyUniqueId][1000], doc[MyUniqueId][2000]
                    
                    
                    if __name__=='__main__':
                       main()
                    

                    Cheers,
                    Manuel

                    MAXON SDK Specialist

                    MAXON Registered Developer

                    ? 1 Reply Last reply Reply Quote 2
                    • ?
                      A Former User @Manuel
                      last edited by A Former User

                      @m_magalhaes Hi Manuel and thank you for this contribution. This code's data, however, is not persisting when I do the following:

                      • run the script to set the data
                      • close and reopen the document.
                      • comment out the lines setting the data (lines 11-19)
                      • run the script to print the data

                      Instead I get this error for doc[MyUniqueId]:

                      TypeError: 'NoneType' object has no attribute '__getitem__'
                      

                      Also, is MyUniqueId supposed to be the PLUGIN_ID? Why is that not being used?

                      Thanks!

                      CairynC 1 Reply Last reply Reply Quote 0
                      • CairynC
                        Cairyn @A Former User
                        last edited by

                        @blastframe For me, it works fine this way. Did you really "close and reopen" the document? Not "save", "close", "load"? Because if you just close the document, the data from the container is gone, which leads to your error message.

                        The Q regarding MyUniqueId vs. PLUGIN_ID is not relevant (probably typed in a hurry), you can use either. But the ID value should come from Maxon in the end, so you avoid collisions with existing IDs.

                        ? 1 Reply Last reply Reply Quote 0
                        • ?
                          A Former User @Cairyn
                          last edited by A Former User

                          @Cairyn I'm a little embarrassed, but you're right. I wasn't saving properly (I think just saving the Script) then going to the document in Recent Files. I'll mark this solved.

                          Thank you all - @Cairyn ,@zipit ,@m_magalhaes .

                          1 Reply Last reply Reply Quote 0
                          • ManuelM
                            Manuel
                            last edited by

                            hi,

                            you could use the same ID, you just have to be sure that you are the only one to use that ID to store datas.
                            That's why we use plugin's ID.

                            Cheers
                            Manuel.

                            MAXON SDK Specialist

                            MAXON Registered Developer

                            ? 1 Reply Last reply Reply Quote 0
                            • ?
                              A Former User @Manuel
                              last edited by A Former User

                              @m_magalhaes Thanks, Manuel.

                              How would I delete the data of an individual sub-BaseContainer in the case of your script?

                              I've tried several methods below but the doc[MyUniqueId][1000] still shows data in the print call.

                              bc = doc.GetDataInstance().GetContainer(MyUniqueId)
                              print bc.RemoveData(1000)
                              # True 
                              print doc[MyUniqueId].RemoveData(1000)
                              # True
                              doc[MyUniqueId].FlushAll()
                                  
                              print doc[MyUniqueId][1000]
                              #hello
                              

                              I was able to delete all of the data this way, but what if I want to keep the data in subBc[2000]?

                              docBC.RemoveData(MyUniqueId)
                              

                              Thank you!

                              1 Reply Last reply Reply Quote 0
                              • ManuelM
                                Manuel
                                last edited by Manuel

                                hello,

                                there's a difference between GetContainer and GetContainerInstance
                                The first return a copy of the container the second the original link.
                                So either you retrieve a copy and set back the container to the parent with SetData and/or SetContainer
                                or you retrieve the original link and the changes are reflected immediately.

                                You can also use del that is pythonic

                                    bc = doc.GetDataInstance().GetContainerInstance(MyUniqueId)
                                    bc.RemoveData(2000)
                                    #del (bc[2000])
                                

                                Cheers,
                                Manuel

                                MAXON SDK Specialist

                                MAXON Registered Developer

                                ? 1 Reply Last reply Reply Quote 1
                                • ?
                                  A Former User @Manuel
                                  last edited by A Former User

                                  @m_magalhaes said in Writing data to the .c4d file:

                                  You can also use del that is pythonic

                                      bc = doc.GetDataInstance().GetContainerInstance(MyUniqueId)
                                      bc.RemoveData(2000)
                                      #del (bc[2000])
                                  

                                  Wonderful, @m_magalhaes , thank you so much!

                                  1 Reply Last reply Reply Quote 0
                                  • First post
                                    Last post