Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python 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

    Store generator's property

    Cinema 4D SDK
    python
    2
    4
    586
    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.
    • bacaB
      baca
      last edited by

      Hi everyone,

      I'm completely misunderstand how to store object's related data.
      Read few posts, but there are common words only... Not sure there would be Read/Write/Copy overrides...

      I'd like to have a selection tag on the Generator object based on UI's bool (CHECKBOX_ID).
      If it's already exist - then use existing, otherwise add it automatically.
      Link should be updated after save/open

      Please point me to a solution, if any.

      CHECKBOX_ID = 1001
      SOME_ID = 5000
      SOME_ID_TAG = 5001
      
      class GeneratorPlugin(c4d.plugins.ObjectData):
        def Init(self, op):
          if op is None: raise RuntimeError("Failed to retrieves op.")
          self.InitAttr(op, bool, CHECKBOX_ID)
          op[CHECKBOX_ID] = True
      
          bc = op[SOME_ID]
          if bc is None:
            print "Data Not Exist"
            bc = c4d.BaseContainer()
            bc[SOME_ID] = c4d.BaseContainer()
          else:
            print "Data Exist", bc.GetLink(SOME_ID_TAG)
          op[SOME_ID] = bc
      
        def GetVirtualObjects(self, op, hh):
          if op is None or hh is None: raise RuntimeError("Failed to retrieves op or hh.")
      
          tmpSel = c4d.BaseSelect()
          # some calculations
      
          tag = op[SOME_ID].GetLink(SOME_ID_TAG)
          if op[CHECKBOX_ID]:
            if not tag:
              tag = c4d.SelectionTag(c4d.Tpolygonselection)
              op.InsertTag(tag)
              op[SOME_ID].SetLink(SOME_ID_TAG, tag)
            tmpSel.CopyTo(tag.GetBaseSelect())
          elif tag:
            tag.Remove()
            op[SOME_ID].RemoveData(SOME_ID_TAG)
      
      
      1 Reply Last reply Reply Quote 0
      • ManuelM
        Manuel
        last edited by

        hello,

        The BaseContainer of an object is saved automatically with the document. As long as you are storing your data in the object's BaseContainer, you don't have to worry to save them with the document.

        Read/Write/Copy need to be override when you are storing data somewhere else. In most of the case, If one of those function is implemented, you have to implement all of them.

        GVO (GetVirtualObjects) isn't the right place to change the scene. See information about threading

        To know if you are on the main thread or not you can use GeIsMainThread

        The right place to do something like this is the Message function.
        You can react to the message MSG_DESCRIPTION_POSTSETPARAMETER to apply some modifications when a parameter have been changed.
        You can also react to the message MSG_MENUPREPARE that is sent before the object is inserted in the scene.

        Be careful that this selection tag shouldn't be moved from the generator (or it will be reset)
        To avoid that, you can change its bit using ChangeNBit

        Here are an example of what you want to do.

            def CreateSelectionTag(self, node):
                #Creates a selection tag. Remove the tag first if it already exist
                bc = node.GetDataInstance()
                if bc is None:
                    return False
                tag = bc.GetLink(ID_TAGLINK)
                if tag:
                    tag.Remove()
                    bc.RemoveIndex(ID_TAGLINK)
        
                tag = c4d.SelectionTag(c4d.Tpolygonselection)
                if tag is None:
                    return False
                tag.ChangeNBit(c4d.NBIT_NO_DELETE, c4d.NBITCONTROL_SET);
                tag.ChangeNBit(c4d.NBIT_NO_DD, c4d.NBITCONTROL_SET);
                node.InsertTag(tag)
                bc.SetLink(ID_TAGLINK, tag)
                return True
                
        
            def RemoveSeletionTag(self, node):
                # Remove the tag 
                bc = node.GetDataInstance()
                if bc is None:
                    return False
                tag = bc.GetLink(ID_TAGLINK)
                if tag is None:
                    return False
                tag.Remove()
                bc.RemoveIndex(ID_TAGLINK)
                return True
        
            def Init(self, op):
                op[ID_CHECKBOX] = True
                return True
            
            def Message(self, node, type, data):
                # MSG_MENUPREPARE is sent before the object (generator here) is inserted in the scene. This is a nice moment to add any tag to the node
                if type == c4d.MSG_MENUPREPARE:
                    print ("Message mainthread ? ", c4d.threading.GeIsMainThread())
                    self.CreateSelectionTag(node)
                # MSG_DESCRIPTION_POSTSETPARAMETER is sent if a parameter have changed. Check here if we should add or remove a tag.
                elif type == c4d.MSG_DESCRIPTION_POSTSETPARAMETER:
                    print ("Message mainthread ? ", c4d.threading.GeIsMainThread())
                    if data['descid'][0].id == ID_CHECKBOX:
                        if node[ID_CHECKBOX]:
                            return self.CreateSelectionTag(node)
                        else:
                            return self.RemoveSeletionTag(node)
                return True
        
            
            
          
            # Override method, should generate and return the object.
            def GetVirtualObjects(self, op, hierarchyhelp):
                print ("GVO mainthread ? ", c4d.threading.GeIsMainThread())
                if op[ID_CHECKBOX]:
                    bc = op.GetDataInstance()
                    tag = bc.GetLink(ID_TAGLINK)
                    if tag:
                        print ("the tag is", tag)
                    else:
                        print ("this should never happen")
                else:
                    bc = op.GetDataInstance()
                    tag = bc.GetLink(ID_TAGLINK)
                    if tag:
                        print ("this should never happen")
                    else:
                        print ("there's no tag and box isn't checked")
        
        
        

        Cheers,
        Manuel

        MAXON SDK Specialist

        MAXON Registered Developer

        bacaB 1 Reply Last reply Reply Quote 0
        • bacaB
          baca @Manuel
          last edited by baca

          Oh, such a rocket science!
          Many thanks Manuel, it seems it works super fine.

          @m_magalhaes said in Store generator's property:

              if op[ID_CHECKBOX]:
                  bc = op.GetDataInstance()
                  tag = bc.GetLink(ID_TAGLINK)
                  if tag:
                      print ("the tag is", tag)
                  else:
                      print ("this should never happen")
              else:
                  bc = op.GetDataInstance()
                  tag = bc.GetLink(ID_TAGLINK)
                  if tag:
                      print ("this should never happen")
                  else:
                      print ("there's no tag and box isn't checked")
          
          1 Reply Last reply Reply Quote 0
          • ManuelM
            Manuel
            last edited by

            hi

            can we considered this thread as resolved ?

            Cheers,
            Manuel

            MAXON SDK Specialist

            MAXON Registered Developer

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