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
    • Recent
    • Tags
    • Users
    • Login

    Object Plugin position in manager

    Scheduled Pinned Locked Moved PYTHON Development
    14 Posts 0 Posters 1.2k Views
    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.
    • H Offline
      Helper
      last edited by

      On 30/09/2013 at 08:16, xxxxxxxx wrote:

      the code does look okish, however two ideas:

      1. The return value of Message() methods in c4d does remain a tricky thing. It is easy
      to freeze c4d with missing calls, even though there have been made some changes in
      R14. I cannot remember to have ran into that problem for NodeData yet, but I guess it 
      is worth a try. Replace your return statement with one of the following:

      return super(MyNodeDataType, self).Message(node, type, data)
      return NodeData.Message(self, node, type, data)

      You should also be aware that the Message() return value follows in c4d the consumption logic
      and is not indicating the success of the operation.

      2. I am not sure when MSG_MENUPREPARE is being sent, but c4d.documents.GetActiveDocument()
      is a statement you usually want to avoid in plugins, as it can easily invoke several problems
      (cloned documents, livetime and so on.) Better sources for the document are either the doc 
      parameter or a node we know (or suspect) to be in the targeted document. So if you do change 
      your code to doc = node.GetDocument() and doc is still None, I would not try to insert the object 
      manually at that point. A better solution might be then a small MessageData plugin.

      1 Reply Last reply Reply Quote 0
      • H Offline
        Helper
        last edited by

        On 30/09/2013 at 12:02, xxxxxxxx wrote:

        MSG_MENUPREAPRE is sent when the node is first inserted into a document. Primitive objects for
        instance create a Phong Tag on themselves with this message. You can send it manually when
        creating an object in a script.

        As I already said, the node is already inserted. You can't insert a node twice, that leads to critical
        reference issues. You first need to remove the node, then insert it again.

        You are of course free to do this, but I do not recommend it. In Cinema 4D, the user is free to
        choose at what place the object should be created. If he would like your object to be inserted
        under the selected object, he'd hold the SHIFT key while pressing the menu button.

        Best,
        -Niklas

        1 Reply Last reply Reply Quote 0
        • H Offline
          Helper
          last edited by

          On 30/09/2013 at 12:48, xxxxxxxx wrote:

          Originally posted by xxxxxxxx

          MSG_MENUPREAPRE is sent when the node is first inserted into a document. Primitive objects for
          instance create a Phong Tag on themselves with this message. You can send it manually when
          creating an object in a script.

          As I already said, the node is already inserted. You can't insert a node twice, that leads to critical
          reference issues. You first need to remove the node, then insert it again.

          You are of course free to do this, but I do not recommend it. In Cinema 4D, the user is free to
          choose at what place the object should be created. If he would like your object to be inserted
          under the selected object, he'd hold the SHIFT key while pressing the menu button.

          Best,
          -Niklas

          Hey,

          I guess I was a bit unclear about the line ' I am not sure when MSG_MENUPREPARE is being  sent', as
          I did know the occasion and meant I did not know when it is sent, after or before the object
          has been inserted into the document.

          1. At least in python you do not have to invoke Remove() before invoking any of the InsertXYZ()
          methods.

          2. I did a little test with an ObjectData plugin of mine (a SplineObject to be more specific ). These
          lines -

          def Message(self, node, mtype, data) :
              """
              """
              [...]
              if mtype == c4d.MSG_MENUPREPARE:
                  print node.GetDocument()
              [...]
          

          will print None to the console for me, indicating that the object is still 'floating' and has not been
          inserted yet. So it is porting towards my assumption, that c4d does not expect the object to be
          inserted at that point yet and doing it manually does not seem to be a good idea ( considering
          the problems the op did report).

          So I am not quite sure if your suggestions do really apply, but I might be wrong.

          1 Reply Last reply Reply Quote 0
          • H Offline
            Helper
            last edited by

            On 30/09/2013 at 13:04, xxxxxxxx wrote:

            Hi Ferdinand,

            Thanks for paying attention, you are correct.

            I somehow had this construct in mind (see below) which leads to Cinema go into an infinite loop.
            But you are absolutely correct about your statement, that it is not  necessary to call the Remove()
            method.

            op.InsertUnder(op) # Invalid, will result in an infinite loop
            

            Seems like I also had #2 wrong in my mind. I thought I was remembering a part where I
            successfully called GetDocument() in MSG_MENUPREPARE, this is why I came to the above
            conclusion which is obviously wrong.

            Drawing a new conclusion from the corrected information, MSG_MENUPREPARE is called before the
            object is inserted into the document, which explains why GetDocument() returns None and why
            Cinema runs into an infinite loop. Cinema probably does not expect you to insert the object in
            MSG_MENUPREPARE, then after it has sent the message, it simply inserts the object and thus
            some objects have invalid references.

            Thanks again Ferdinand,
            Best - Niklas

            1 Reply Last reply Reply Quote 0
            • H Offline
              Helper
              last edited by

              On 30/09/2013 at 13:40, xxxxxxxx wrote:

              Well, for me, it's stuck on the return for sure.

              def Message(self, node, type, data) :
                      if type == c4d.MSG_MENUPREPARE:
                          doc = c4d.documents.GetActiveDocument()
                          print doc
                          place = doc.GetActiveObject()
                          print place
                          node.InsertUnder(place)
                          print "success"
                      return True
              

              and console prints this:

              <c4d.documents.BaseDocument object called '' with ID 110059 at 0x000000000F1ED670>
              <c4d.BaseObject object called 'Cube/Cube' with ID 5159 at 0x0000000006AE4890>
              success

              and AFTER that it locks. So you can define the active document in the MENUPREPARE for sure.

              but if I use node.GetDocument() it equals to None, so the object itself isn't in the document yet.
              So any ideas how to do it ?
              @ Niklas: I need to insert it before the selected object 🙂 i don't know why i started testing with InsertAfter(). So any ALT or SHIFT will not do it.

              1 Reply Last reply Reply Quote 0
              • H Offline
                Helper
                last edited by

                On 30/09/2013 at 15:09, xxxxxxxx wrote:

                Do not use doc = c4d.documents.GetActiveDocument()in plugin code (except for command data
                plugins). C4d does duplicate the document for rendering which will render that code useless as
                GetActiveDoucment() will always return the active document in the editor (so that you are using
                the wrong document). It also does introduce possible problems with dead objects. If you cannot
                get hold of the document a node is sitting in with GeListNode.GetDocument(), it is a strong 
                indicator that you should look for a later point of interception.

                As I wrote already in my first posing the most straight forward option would be a MessageData
                plugin monitoring your scene structure (or more specifically the top object and the current 
                selection). If you do REALLY want to do it from within your ObjectData plugin you could do the 
                following.

                1. To be extra sure that the whole process is only invoked once I would add a virtual element to 
                the objects description, indicating if the object has already been moved once or not. You will also
                need some boolean flag value in your class indicating that the node has to be moved.

                2. In the Message method ( you could also use Init(), the object isn't yet alive there either ) store 
                the active object selection as a class member, using some clunky GetActiveDocument() code.

                3. One of the first things which will happen after the node has been initialized is that c4d will build
                its cache and call GVO. So check in GVO if your object is flagged for being relocated, if so, use the 
                stored object selection to modify the location of the node passed to GVO.

                Please let me stress again, that this actually rather HACKY and BAD code. The separate
                MessageData plugin would be a much cleaner solution.

                edit : the general flaw in the logic of your code is ( now i do understand what niklas meant with
                op.InsertUnder(op)), that at the point when the object is alive the active selection will be the 
                object itself, as c4d is selecting new objects. that is why you will need that 2 step approach and
                also why a MessageData solution would be much better, as it wouldn't need such hacks.

                1 Reply Last reply Reply Quote 0
                • H Offline
                  Helper
                  last edited by

                  On 30/09/2013 at 15:31, xxxxxxxx wrote:

                  thanks for the hints. I'm just starting with python, so obviously i have some digging to do 🙂
                  actually the "data" entry from Message(self, node, type, data) also returns the document, but it seems that this will not help me in anyway. I'll try to figure out the Message plugin solution.

                  1 Reply Last reply Reply Quote 0
                  • H Offline
                    Helper
                    last edited by

                    On 30/09/2013 at 16:09, xxxxxxxx wrote:

                    You mean data is a BaseDocument for MSG_MENUPREPARE ? The type of data actually depends on the 
                    type of the message, I didn't  know that it is a BaseDocument for MSG_MENUPREPARE, but it does make 
                    sense, as the ID is there to let you do additional setup stuff.

                    Just to be clear, using the hacky way wouldn't let the world end, its just rather hacky and you should 
                    be aware of it. Generally directly modifying the active scene from within a NodeData plugin is a
                    rather unusual thing to do.

                    1 Reply Last reply Reply Quote 0
                    • H Offline
                      Helper
                      last edited by

                      On 01/10/2013 at 02:02, xxxxxxxx wrote:

                      MessageData plugin didn't helped. I couldn't find a message to listen that will suit my needs. But I managed to do it with CommandData plugin. Now it seems so logical to do it that way 🙂 Thanks a lot for the hints. Till now I only made some simple python scripts to help my work, but i got so hooked up with python, that i really want to learn it in depth. I'll show you what is the plugin that i'm trying to make later. Actually I think it will be quite usefull.

                      1 Reply Last reply Reply Quote 0
                      • H Offline
                        Helper
                        last edited by

                        On 01/10/2013 at 08:01, xxxxxxxx wrote:

                        The core message you would use in MessageData plugin would be simply EVMSG_CHANGE.
                        A very rough layout would be :

                        1. when the class instance is constructed store the active selection and the topmost object.
                        2. each time EVMSG_CHANGE occurs, update your topmost object, if it is of the desired type
                        and  the current selection move it to your previously stored selection. if not, overwrite your
                        selection cache.
                        3. to cover some special cases you could also add a general monitoring of your object type
                        XYZ so that it doesn't get accidentally moved, when the user does select it and moves it to
                        the top of the scene hierarchy.

                        A CommandData is of course also a good solution however it won't work if you would instantiate
                        your type programmatically (and use the actual object and not directly your CommandData plugin ID).

                        Happy rendering,
                        Ferdinand

                        1 Reply Last reply Reply Quote 0
                        • H Offline
                          Helper
                          last edited by

                          On 01/10/2013 at 13:53, xxxxxxxx wrote:

                          yes, i that's what I did, but I didn't like that it EVMSG_CHANGE occurs all the time, I didn't feel that's what i need. With the CommandData plugin the code is called only once, on creation of the object, so it's cleaner for me. Also there won't be a problem with the actual ObjectPlugin, cause it has the flag "c4d.PLUGINFLAG_HIDE", so you can't find it as a button and you can't even call it as a command. Or am I wrong ?

                          1 Reply Last reply Reply Quote 0
                          • H Offline
                            Helper
                            last edited by

                            On 02/10/2013 at 12:20, xxxxxxxx wrote:

                            http://rapidgator.net/file/73b4cf9bd384f1c3069d228786850219/Group_Object.zip.html

                            here it is

                            1 Reply Last reply Reply Quote 0
                            • H Offline
                              Helper
                              last edited by

                              On 03/10/2013 at 04:51, xxxxxxxx wrote:

                              Originally posted by xxxxxxxx

                              yes, i that's what I did, but I didn't like that it EVMSG_CHANGE occurs all the time, I didn't feel that's what i need. With the CommandData plugin the code is called only once, on creation of the object, so it's cleaner for me. Also there won't be a problem with the actual ObjectPlugin, cause it has the flag "c4d.PLUGINFLAG_HIDE", so you can't find it as a button and you can't even call it as a command. Or am I wrong ?

                              no you are absolutely right, it is a perfectly valid way. about EVMSG_CHANGE and that it does
                              seem unreasonably computational expensive - it is a bit weird and I was also irritated at first,
                              but it is actually the intended way. I did ask here some time ago on how to get notified, if
                              the active document has been changed and the answer of one of the devs was EVMSG_CHANGE.
                              EVMSG_CHANGE is there to check such stuff like oldx != newx, so it is ok to use it in that way.

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