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 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