Storing a part of the hierarchy



  • @zipit, I got the code from another thread: https://plugincafe.maxon.net/topic/11802/writing-data-to-the-c4d-file/19
    And if you change

    subBc[2000] = "world!"
    

    to

    subBc[2000] = op
    

    it also works!

    I tried

    subBc.SetLink(2000, newDoc)
    

    and indeed it does not work. It returns a None on reading back the subcontainer after storing the file.



  • @zipit, yes I know that functionality (and use it often).
    However, although it is hidden it still consumes cpu power.
    We like to minimalize cpu power by converting a node using csto, hide the node and disabling generators and deformers in the node.



  • Hi,

    subBc[2000] = "world!"
    

    to

    subBc[2000] = op
    

    That is expected as op is also an C4DAtom.

    it also works!

    I tried

    subBc.SetLink(2000, newDoc)
    

    and indeed it does not work. It returns a None on reading back the subcontainer after storing the file.

    The method SetLink() does not have a (boolean) return type. So this is to be expected too. I am not quite sure if you got my point, so here is a modified version of your first script - which you assume to be "working" as it printed back your document. I did modify it in such a way, that it does not work any more - I am really good at this specific task ;). I hope the code and the comments make more clear what I am trying to convey: That you are not storing your document, but a link to it.

    import c4d
    
    PLUGIN_ID = 1234567
    MyUniqueId = 456789
    
    def main():
        #retrieves the document baseContainer
        docBC = doc.GetDataInstance()
    
        sel = doc.GetSelection()    # !!! only select the parent, not the children
        newDoc = c4d.documents.IsolateObjects(doc, sel)
    
        #create a sub-BaseContainer
        subBc = c4d.BaseContainer()
        subBc[1000] = "hello"
        subBc[2000] = newDoc
        
        # Get the type of the ID we set
        print "ID 2000 is a link", subBc.GetType(2000) == c4d.DA_ALIASLINK
        
        # do the same thing in green. That SetLink() returns None
        # is expected as it has no return value (which is implictly
        # None in Python)
        subBc.SetLink(2000, newDoc)
        
        print "ID 2000 is a link", subBc.GetType(2000) == c4d.DA_ALIASLINK
    
        # 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 "\nDeleting newDoc...\n"
        # This part is a bit dodgy since Pythons garbage collector cannot
        # be trusted. But what I am trying to show is that you stored
        # a reference, not an object. For me it works here, but in some cases
        # an object can linger even after marking it for garbage collection.
        newDoc.Flush()
        del(newDoc)
        
        # Print the values stored in our container.
        for cid, value in doc.GetDataInstance().GetContainer(MyUniqueId):
            print cid, value
    
    
    if __name__=='__main__':
       main()
    

    this should print out something like:

    ID 2000 is a link True
    ID 2000 is a link True
    1000 hello
    2000 <c4d.documents.BaseDocument object called '' with ID 110059 at 0x00000135BC7F9030>
    
    Deleting newDoc...
    
    1000 hello
    2000 None
    >>> 
    

    Cheers
    zipit



  • Thanks for the explanation.

    Two questions:

    1. the line <c4d.documents.BaseDocument object called '' with ID 110059 at 0x00000135BC7F9030> always show a strange name ''? Why is it not showing the name of the document?

    2. Back to the main questions, what to do, to store the node in scene file.



  • hello,

    1 - what kind of strange name ?

    2 -

    you can store the data itself in the tag and than with the function read and write store them in the Scenefine
    I'm using a file on the disk on this example but that should work with the HyperFile link provide by the read and write functions.

    Be aware that HyperFile.WriteMemory is storing byte sequences that will be platform dependent.

    import c4d
    from c4d import gui
    # Welcome to the world of Python
    import os
    
    
    # Main function
    def main():
        
        path =  c4d.storage.LoadDialog(c4d.FILESELECTTYPE_SCENES, flags=c4d.FILESELECT_DIRECTORY)
        path = os.path.join(path, "prout.txt")
        
        # using a MemoryFileStructure to store a document
        mfs = c4d.storage.MemoryFileStruct()
        mfs.SetMemoryWriteMode()
        
        newdoc = c4d.documents.IsolateObjects(doc , [op])
        # Save the document to the MemoryFileStructure
        c4d.documents.SaveDocument(newdoc, mfs, c4d.SAVEDOCUMENTFLAGS_NONE, c4d.FORMAT_C4DEXPORT)
        
        #Retrieve the data and store it somewhere, could be self.myData
        myData = mfs.GetData()
        
       
       
        #Save the data to a hyperfile
        myFile = c4d.storage.HyperFile()
        if not myFile.Open(0, path, c4d.FILEOPEN_WRITE, c4d.FILEDIALOG_NONE):
            raise RuntimeError("Failed to open the HyperFile in write mode.")
        
        # Store the size
        myFile.WriteInt32(myData[1])
        # Store the data itself
        if myFile.WriteMemory(myData[0]) is False:
            raise ValueError("can't write the file")
        myFile.Close()
    
        
        # Read the data from the HF
        if not myFile.Open(0, path, c4d.FILEOPEN_READ, c4d.FILEDIALOG_NONE):
            raise RuntimeError("Failed to open the HyperFile in read mode.")
        
        size = myFile.ReadInt32()
        data = myFile.ReadMemory()
        myFile.Close()
        
        #Set the MFS
        mfs2 = c4d.storage.MemoryFileStruct()
        mfs2.SetMemoryReadMode(data,size)
        
         
        c4d.documents.MergeDocument(doc, mfs2, c4d.SCENEFILTER_OBJECTS)
        c4d.EventAdd()
    
    # Execute main()
    if __name__=='__main__':
        main()
    

    Once again, be aware of where you are modifying the scene (on main thread and not elsewhere)

    by the way, are you going to use c++ or python at the end ? (just for the tags of this thread)

    Cheers,
    Manuel



  • Great, thank you very much.
    I am beginning to see the light.

    And yes, my fault, apparently I indicated it as c++, but I am doing it in Python.

    About your warning.
    My plan was to do it all in a tag plugin.
    There I can have the interface, do the isolate and the read/write in a hf.
    Or is it better to do it in a Object plugin?

    9f1b1f56-1bff-4864-ba56-8cf0c4036897-image.png



  • Hi,

    @pim said in Storing a part of the hierarchy:

    1. the line <c4d.documents.BaseDocument object called '' with ID 110059 at 0x00000135BC7F9030> always show a strange name ''? Why is it not showing the name of the document?

    Not quite sure what you do mean by that:

    1. The fact that the it prints the empty string for the document name is probably because you run the script on a unsaved document. This whole untitled_x.c4d stuff you see in c4d app is all smoke and daggers. An unsaved document will return the empty string for GetName().
    2. If you mean how objects are printed out, this is because of the way it is convention to implement __repr__() for an object. I found that obsession with memory addresses also always quite bizarre, but, hey, everyone is doing it ;)

    Cheers
    zipit



  • @pim said in Storing a part of the hierarchy:

    My plan was to do it all in a tag plugin.
    There I can have the interface, do the isolate and the read/write in a hf.
    Or is it better to do it in a Object plugin?

    Hi, it does not really matter what kind of NodeData you use, what @m_magalhaes meant, was that you should be careful with the threaded context of methods like Execute() in TagData or GetVirtualObjects() in ObjectData. When you execute your code from a method that is executed from the main thread, you are fine (e.g. NodeData.Message()). You can always check there with c4d.threading.GeIsMainThread() if you are in the main thread to be extra sure.

    Cheers
    zipit



  • An ObjectData (generator) would be a bit better for that. But you are exploring possibilities, that's also the way to find new solutions / workflow.

    About my warning it's just a reminder. You will have so sent message probably and use a MessageData to react to that message in order to do some action in the main thread.

    Cheers,
    Manuel



  • Thanks for all the support.
    I will use all the knowledge gained and start testing.
    I am sure, I will be back with more questions.

    -Pim


Log in to reply