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

    Detect Hirarchy Change in a tag

    Cinema 4D SDK
    2
    3
    396
    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.
    • C
      cgweasel
      last edited by

      ok, well. I guess i have to find another way.

      is there a way for a tag plugin to notice, that the object it is on has changed within the hierarchy? like the MSG_CHANGE? That could help me 🙂

      1 Reply Last reply Reply Quote 0
      • M
        m_adam
        last edited by m_adam

        Hi @cgweasel I forked your topic, in the future please create a new topic each time you have a question with a topic that is unrelated to the current discussion.

        With that said there is no 100% reliable way to do it, the best way would be to store the neighbor hierarchy (GetUp,GetPred,GetNext) and then add an execution step as Initial so within the Execute method you can check for these objects.

        Find bellow and example adapted from py-look-at-camera example. The important methods to check are:

        • __init__ to initialize the cache value
        • AddToExecution to add the Initial state execution
        • isHierarchyChanged to check if the cache changed
        • updateCachedHierarchy to update the cache
        • Execute with priority == c4d.EXECUTIONPRIORITY_INITIAL that will check the cache, and print a message when the hierarchy changed.
        import os
        import c4d
        
        # Be sure to use a unique ID obtained from www.plugincafe.com
        PLUGIN_ID = 1028284
        
        
        class LookAtCamera(c4d.plugins.TagData):
            """Look at Camera"""
        
            def __init__(self):
                self._up = None
                self._pred = None
                self._next = None
        
            def Init(self, node):
                """Called when Cinema 4D Initialize the TagData (used to define, default values).
        
                Args:
                    node (c4d.GeListNode): The instance of the TagData.
        
                Returns:
                    True on success, otherwise False.
                """
                self.InitAttr(node, bool, c4d.PYLOOKATCAMERA_PITCH)
                node[c4d.PYLOOKATCAMERA_PITCH] = True
        
                pd = c4d.PriorityData()
                if pd is None:
                    raise MemoryError("Failed to create a priority data.")
        
                pd.SetPriorityValue(c4d.PRIORITYVALUE_CAMERADEPENDENT, True)
                node[c4d.EXPRESSION_PRIORITY] = pd
                return True
        
            def AddToExecution(self, tag, prioList):
                """Called By Cinema 4D to determine when in the Execution Pipeline the Execute method of this tag should be called.
        
                Args:
                    tag (c4d.BaseTag): The instance of the TagData.
                    prioList (c4d.plugins.PriorityList): The priority list to add your tag’s execution points to.
        
                Returns:
                    True if the hierarchy changed, otherwise False.
                """
        
                # Retrieve the user defined priority
                storedPriority = tag[c4d.EXPRESSION_PRIORITY]
                storedPriorityValue = storedPriority.GetPriorityValue(c4d.PRIORITYVALUE_MODE) + \
                                      storedPriority.GetPriorityValue(c4d.PRIORITYVALUE_PRIORITY)
        
                # Add an execution during the Initial phase, this is when we will check for hierarchy change
                prioList.Add(tag, c4d.EXECUTIONPRIORITY_INITIAL, 0)
        
                # Add the user defined execution phase, therefor the Execute method will be called 2 times.
                prioList.Add(tag, storedPriorityValue, 0)
                return True
        
            def isHierarchyChanged(self, obj):
                """Check if any of the cached neighbor hierarchy is different from the actual one.
        
                Args:
                    obj (c4d.BaseObject): The host object to compare the hierarchy from.
                    
                Returns:
                    True if the hierarchy changed, otherwise False.
                """
                up = obj.GetUp()
                if up != self._up:
                    return True
        
                pred = obj.GetPred()
                if pred != self._pred:
                    return True
        
                next = obj.GetNext()
                if next != self._next:
                    return True
        
                return False
        
            def updateCachedHierarchy(self, obj):
                """Update the cached neighbor hierarchy.
        
                Args:
                    obj (c4d.BaseObject): The host object to retrieve the hierarchy from.
                """
                self._up = obj.GetUp()
                self._pred = obj.GetPred()
                self._next = obj.GetNext()
        
            def Execute(self, tag, doc, op, bt, priority, flags):
                """Called by Cinema 4D at each Scene Execution, this is the place where calculation should take place.
        
                Args:
                    tag (c4d.BaseTag): The instance of the TagData.
                    doc (c4d.documents.BaseDocument): The host document of the tag's object.
                    op (c4d.BaseObject): The host object of the tag.
                    bt (c4d.threading.BaseThread): The Thread that execute the this TagData.
                    priority (EXECUTIONPRIORITY): Information about the execution priority of this TagData.
                    flags (EXECUTIONFLAGS): Information about when this TagData is executed.
                """
                if priority == c4d.EXECUTIONPRIORITY_INITIAL:
                    if self.isHierarchyChanged(op):
                        self.updateCachedHierarchy(op)
                        print("Hierarchy Changed")
        
                        # We don't want to execute the logic of our tag during this phase except if the user asked for it
                        storedPriority = tag[c4d.EXPRESSION_PRIORITY]
                        storedPriorityValue = storedPriority.GetPriorityValue(c4d.PRIORITYVALUE_MODE) + \
                                              storedPriority.GetPriorityValue(c4d.PRIORITYVALUE_PRIORITY)
                        if storedPriorityValue != c4d.EXECUTIONPRIORITY_INITIAL:
                            return c4d.EXECUTIONRESULT_OK
        
                # Retrieves the current active base draw
                bd = doc.GetRenderBaseDraw()
                if bd is None:
                    return c4d.EXECUTIONRESULT_OK
        
                # Retrieves the active camera
                cp = bd.GetSceneCamera(doc) if bd.GetSceneCamera(doc) is not None else bd.GetEditorCamera()
                if cp is None:
                    return c4d.EXECUTIONRESULT_OK
        
                # Calculates the position to target
                local = cp.GetMg().off * (~(op.GetUpMg() * op.GetFrozenMln())) - op.GetRelPos()
        
                # Calculates the rotation to target
                hpb = c4d.utils.VectorToHPB(local)
        
                if not tag[c4d.PYLOOKATCAMERA_PITCH]:
                    hpb.y = op.GetRelRot().y
                hpb.z = op.GetRelRot().z
        
                # Defines the rotation
                op.SetRelRot(hpb)
                
                return c4d.EXECUTIONRESULT_OK
        
        
        if __name__ == "__main__":
            # Retrieves the icon path
            directory, _ = os.path.split(__file__)
            fn = os.path.join(directory, "res", "tpylookatcamera.tif")
        
            # Creates a BaseBitmap
            bmp = c4d.bitmaps.BaseBitmap()
            if bmp is None:
                raise MemoryError("Failed to create a BaseBitmap.")
        
            # Init the BaseBitmap with the icon
            if bmp.InitWith(fn)[0] != c4d.IMAGERESULT_OK:
                raise MemoryError("Failed to initialize the BaseBitmap.")
        
            c4d.plugins.RegisterTagPlugin(id=PLUGIN_ID,
                                          str="Py - LookAtCamera",
                                          info=c4d.TAG_EXPRESSION | c4d.TAG_VISIBLE,
                                          g=LookAtCamera,
                                          description="Tpylookatcamera",
                                          icon=bmp)
        

        Side note, we will be away the 26th and 27th December, so don't be surprise by the delay if you have follow-up questions, for more information see No support on 26/12 and 27/12.

        Cheers,
        Maxime.

        MAXON SDK Specialist

        Development Blog, MAXON Registered Developer

        1 Reply Last reply Reply Quote 0
        • M
          m_adam
          last edited by

          Hello @cgweasel,

          without further questions or postings, we will consider this topic as solved by Friday 02/06/2023 and flag it accordingly.

          Thank you for your understanding,
          Maxime.

          MAXON SDK Specialist

          Development Blog, MAXON Registered Developer

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