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
    1. Maxon Developers Forum
    2. paulgolter
    3. Posts
    P
    • Profile
    • Following 0
    • Followers 0
    • Topics 3
    • Posts 12
    • Best 0
    • Controversial 0
    • Groups 0

    Posts made by paulgolter

    • RE: Python: PluginMessage: Execute callback on plugin register and unregister event

      Hey @ferdinand

      I still do not 100% understand why this entails you having to poke around in the boot sequence of Cinema 4D. You should just register your plugin normally (there is no alternative to that)

      I think it's mainly because I didn't know what the proper way of doing it was. Reading the docs I thought I needed to use c4d.C4DPL_INIT or c4d.C4DPL_STARTACTIVITY to register my plugin stuff / execute my own startup code. I know there are the c4d plugin examples, but maybe it would be nice to add the "proper" way of registering a plugin to the docs.

      Python plugins cannot be disabled in Cinema 4D. You can reload them, but not disable them. You also cannot unregister a plugin.

      Aha also some good information that I was not aware of!

      And to the server:
      I am not running a server inside of cinema. It is running on some other machine in the internet. I am only connecting to it via a httpx.AsyncClient client. For this reason and some other technical reasons the client needs to run in a separate thread, but all of that works fine and we are even using the c4d.C4DThread for this.

      But you answered my question of this thread already, thanks 🙂

      posted in Cinema 4D SDK
      P
      paulgolter
    • RE: Python: PluginMessage: Execute callback on plugin register and unregister event

      Hey @ferdinand

      I see!

      Maybe you could try to explain on a more abstract level what you are trying to achieve

      In short, I am building a python project, that depends on being able to communicate with a webserver. It sends out things when certain events happen in cinema and also receives signals via websockets to execeute certain actions. The communication with the server is all async and runs inside of a thread to not block the dccs ui.

      Most dccs that enable / disable plugins, have some sort of functions or event that you can hook in when this happens. That way I can for instance, when my plugins is loaded, establish a connection with the webserver and when it is unloaded making sure that I gracefully shutdown the connection, the async loop as well as the thread.

      posted in Cinema 4D SDK
      P
      paulgolter
    • RE: Setting XRef options via python?

      @ferdinand ok I will open another thread for this 🙂

      posted in Cinema 4D SDK
      P
      paulgolter
    • RE: Python: PluginMessage: Execute callback on plugin register and unregister event

      Hey @ferdinand,

      thanks for the detailed background info. Would have never found that out on my own!

      Ok currently I am using the regular python way to call my register() function, which register my message and object plugins:

      if __name__ == "__main__":
          register()
      

      If i try to replace that with:

      def PluginMessage(id: int, data: Any) -> bool:
          if id == c4d.C4DPL_STARTACTIVITY:
              register()
              return True
      

      I get the error: OSError:cannot find pyp file - plugin registration failed

      So i guess just like you said, some calls are still failing. Then I will stick to registering the plugin with the simple if __name__ == "__main__" way and unregistering works fine with the C4DPL_ENDACTIVITY event.

      posted in Cinema 4D SDK
      P
      paulgolter
    • RE: Python: Cinema exit event

      @spedler thanks for your quick reply!

      As you suggested I tried catching the C4DPL_ENDACTIVITY and that works. Thanks!

      But for some reason I can't seem to catch the C4DPL_END that you mentioned.

      Check out this thread where I posted that problem. Would love to hear if you got that to work somehow!

      posted in Cinema 4D SDK
      P
      paulgolter
    • Python: Cinema exit event

      Hey all,

      Is there any way to catch a cinema application exit event?

      I need to do execute code just before cinema shuts down.

      Note: I have set up a cinema python plugin. So if cinema shuts down the plugin before exit and I am able to listen to a plugin unregister event, that would also work.

      All the best

      posted in Cinema 4D SDK python
      P
      paulgolter
    • Python: PluginMessage: Execute callback on plugin register and unregister event

      Hey all,

      I am currently facing the issue that I want to execute code when my cinema python plugin gets registered and unregistered by cinema or a user.

      As i understand from the docs I should be able to listen to events in my .pyp file of my plugin by adding a function called PluginMessage.

      The event ids I am interested in are:

      C4DPL_INIT Initialize the plugin, calling PluginStart.
      C4DPL_END End the plugin, calling PluginEnd

      def PluginMessage(id: int, data: Any) -> bool:
          # ID's don't match up
          if id == c4d.C4DPL_INIT:        
              register()
              return True
      
          if id == c4d.C4DPL_END:
              unregister()
              return True
      
          return False
      

      The problem is that the incoming event ids never seems to match up.

      Any idea what I am doing wrong?

      posted in Cinema 4D SDK python
      P
      paulgolter
    • RE: Setting XRef options via python?

      I know this thread was closed, I am facing the same issue tough.

      Is there any way to solve this somehow in cinema 2024 @ferdinand ?

      Main problem is, if pipelines want to do some dependency tracking, it's very hard to find the absolute path of the xref if ""Relative to Project" is off.

      Especially beacuse the realtive path being shown is simply random sometimes but cinema still manages to resolve it somehow.
      As the logic of how this relative path is resolved, or what the 'project' is that cinema uses for resolving is unclear, it's impossible to replicate this on our end in python.

      posted in Cinema 4D SDK
      P
      paulgolter
    • RE: Python Api: Document Events

      Hey @ferdinand

      A timer is however not necessary from the Cinema side of things when you implement the scene traversal correctly; you can just evaluate the scene on each EVMSG_CHANGE and there comes no big performance penalty with that.

      Can you be more specific how one does scene traversal correct or incorrect in python?

      For example to get all object of a certain type I currently have this code:

      def recurse_hierarchy(
          obj: c4d.BaseObject, hierarchy_list: List, obj_type: Optional[int] = None
      ) -> None:
          while obj:
              if not obj_type or obj.CheckType(obj_type):
                  hierarchy_list.append(obj)
              recurse_hierarchy(obj.GetDown(), hierarchy_list, obj_type)
              obj = obj.GetNext()
      
      # Get all cameras 
      doc = c4d.documents.GetActiveDocument()
      obj_list = []
      recurse_hierarchy(doc.GetFirstObject(), obj_list, obj_type=c4d.Ocamera)
      

      About the efficieny I was thinking if I traverse the scene everytime EVMSG_CHANGE is being fired i do it way more often compared to doing it every 3 seconds or so, which would be enough for me. Correct me if I'm wrong!

      I assume you mean MAXON_CREATOR_ID with 'the creator id', right?

      Yes that is what I meant. Thanks for the detailed explanation.

      Take a look at the script from the other thread, it also does exactly that, including capturing when a light is being renamed.

      Ah yes I kind of missed the part where you also store a hash sum of each object in the scene cache with: obj.GetDirty(c4d.DIRTYFLAGS_DATA).

      I implemented this as well, and if anything changes with the node I re-query the node information I am intersted in, which works. Thanks!

      posted in Cinema 4D SDK
      P
      paulgolter
    • RE: Python Api: Document Events

      Hey @ferdinand

      Thanks again for the detailed answer. I was able to solve it somehow with your tips.

      The solution I have now is a combination of 2 systems.

      01. Object Cache Refresher

      I have a c4d.plugins.MessageData plugin that runs every 2 seconds and compares a cached list of object ids with the current objects ids in the scene. That way I can detect what was deleted and added.

      I am using the creator id of each object that you described in this post which was useful.

      class ObjectCacheRefresher(c4d.plugins.MessageData):
      
          def GetTimer(self):
              return 2000
      
          def CoreMessage(self, id: int, bc: c4d.BaseContainer):
              if id == c4d.MSG_TIMER:
                  refresh_object_id_cache()
              return True
      

      02. Custom Node

      On top of this I added a custom node that can listen to document events in its Message function.

      class CustomNode(c4d.plugins.ObjectData):
      
          def Message(self, node: c4d.GeListNode, type: int, data: Any):
              if type == c4d.MSG_DOCUMENTINFO:
      
                  logger.debug("Document event: %i data: %s", type, data)
      
                  if data["type"] == c4d.MSG_DOCUMENTINFO_TYPE_LOAD:
                      on_scene_loaded()
      
                  if data["type"] == c4d.MSG_DOCUMENTINFO_TYPE_SAVE_AFTER:
                      on_scene_save()
      
                  if data["type"] == c4d.MSG_DOCUMENTINFO_TYPE_SETACTIVE:
                      on_scene_activate()
      
                  if data["type"] == c4d.MSG_DOCUMENTINFO_TYPE_MERGE:
                      on_scene_merge()
              return True
      

      This node needs to be present in the scene tough. I solved this as you suggested with an other MessageData plugin that ensures this is node is added in the scene once.

      This plugin also uses a timer instead of the EVMSG_CHANGE event, as this was sufficient for me and feels less spammy.

      With custom_node.ChangeNBit(c4d.NBIT_OHIDE, c4d.NBITCONTROL_SET) i could hide the node as you noted.

      class NodeAdder(c4d.plugins.MessageData):
      
          def GetTimer(self):
              return 2000
      
          def CoreMessage(self, id: int, bc: c4d.BaseContainer):
              if id == c4d.MSG_TIMER:
                  ensure_event_listener_node()
              return True
      

      TODO

      What I am currently still trying to figure out:

      1. Detect object rename events. In the current approach, I am using the creator id which does not seem to change when the node is renamed.

      2. Detect parameter changes. I would like to detect if certain paramters of certain nodes changed . Including user data parameters.

      If you have any input on these 2 points I would love to hear them.

      Thanks again

      posted in Cinema 4D SDK
      P
      paulgolter
    • RE: Python Api: Document Events

      Hey @ferdinand,

      Thanks for your detailed answer first of all!

      To give a simplified background of what I am trying to do:
      I have a server on the web that stores information about my current cinema session. It should be as reactive as possible. The idea is to update the information on that server sparsely once certain cinema events are triggered to avoid having to send a full update in a specified time interval.

      You pointed out the EVMSG_CHANGE event. As I understand this is being triggered on almost all events (eg. if c4d.EventAdd() is being called). This would be way to spammy for me and I would resort using a timer with a fixed interval and scan the scene for the information that I am interested in and code my own sparse change detection logic.

      • You will not be able to receive MSG_DOCUMENTINFO messages in a command

      Thanks for the info, I think I was confused about this because in the doc it says:

      The following messages can be received in the Message methods of CommandData, FalloffData, NodeData, SculptBrushToolData, and ToolData interfaces and their derived interfaces.

      • You will need a proper node for this, such as an object, tag, material, shader, or scene hook (C++ only)

      I have read about the scene hooks as well, unfortunately as you said, they are only available in C++.

      Adding a 'custom hidden' node that is able to catch some of the events that I am interested in sounds like a solution to me tough. At least for some events.

      Could you give me a headstart how I would go about adding a custom node in my plugin that can catch events and making sure this node always exists when I start up cinema or load a new scene?

      All the best

      posted in Cinema 4D SDK
      P
      paulgolter
    • Python Api: Document Events

      Hey all,

      My goal is pretty simple:

      In Python I want to execute callback functions for a couple of different events. Mostly document events such as:

      • Document Saved
      • Document Loaded
      • Object / Node created
      • Object / Node deleted

      I am very confused how I can achieve this.

      I understand that cinema has different kinds of plugins such as Message, Object, CommandData plugins and more. Each of those plugins has some function which you can re-implement to receive messages. So far so good.

      I tried to use all of those plugins, but could not achieve my goal.
      From what I read in the message system manual it seems like i would need to listen to the event with the id: c4d.MSG_DOCUMENTINFO, which can be received among other plugins by a CommandData plugin.

      My super simple CommandData plugins looks like this:

      class MyCommandDataPlugin(c4d.plugins.CommandData):
          def Message(self, type: int, data: Any):
              if type == c4d.MSG_DOCUMENTINFO:
                  logger.debug("Document event: %i data: %s", type, data)
              return True
      

      This does not log anything if I save / open a document tough.

      The next topic, I could not event test yet, is that on top of the 'generic' c4d.MSG_DOCUMENTINFO event type there seem to be more document specific events such as:
      c4d.MSG_DOCUMENTINFO_TYPE_SAVE_AFTER
      c4d.MSG_DOCUMENTINFO_TYPE_LOAD

      I have no idea where and how I can check for those either.

      I would really appreciate some help on this topic.

      posted in Cinema 4D SDK python
      P
      paulgolter