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
    • Register
    • Login
    1. Maxon Developers Forum
    2. Anlv
    Offline
    • Profile
    • Following 0
    • Followers 0
    • Topics 4
    • Posts 19
    • Groups 0

    Anlv

    @Anlv

    Motion and graphic designer, developer of third-party plugins for Cinema 4D and Photoshop.

    4
    Reputation
    4
    Profile views
    19
    Posts
    0
    Followers
    0
    Following
    Joined
    Last Online
    Email [email protected]
    Age 34

    Anlv Unfollow Follow

    Best posts made by Anlv

    • RE: How to start a new line in plugin help with localization?

      Another small tip: you can simply use a single <br> for line breaks — there’s no need to use <b> or </b>.

      Also, just like in the script example, scripts can support localized language strings as well:

      """
      Name-US:Example
      Name-CN:示例
      Description-US:Example line 1.<br>Example line 2.<br>Example line 3.
      Description-CN:示例第 1 行。<br>示例第 2 行。<br>示例第 3 行。
      """
      
      posted in Cinema 4D SDK
      AnlvA
      Anlv
    • [Free Plugin]Plugin Debug Manager v1.3.0— Python Plugin Reloading for Cinema 4D

      Hi everyone, I’m releasing Plugin Debug Manager, a debugging utility for Cinema 4D Python plugin development.

      When working on a .pyp plugin, changing a single entry file can otherwise require reloading every Python plugin—or restarting Cinema 4D. Plugin Debug Manager reads the currently registered Python plugins and lets developers reload only the entries they are testing.

      Main features:

      • Reads registered .pyp and .pypv plugins from Cinema 4D
      • Groups multiple registrations by their actual entry-file path
      • Displays plugin names, icons, decimal IDs, registration types, and full paths
      • Filters entries by filename or plugin ID
      • Reloads one plugin, selected plugins, or all reloadable plugins
      • Supports click-and-drag checkbox painting for batch selection
      • Persists checked entries and can move them to the top on demand
      • Provides Reload Plugin, Reload All, Fold All, and Unfold All context commands
      • Locates plugin files in Explorer or Finder through c4d.storage.ShowInFinder()
      • Continues processing when an individual plugin fails to reload

      Implementation details:

      • Registry entries are collected with c4d.plugins.FilterPluginList(c4d.PLUGINTYPE_ANY, True)
      • Entry files and registration metadata are obtained through BasePlugin.GetFilename(), GetID(), and GetType()
      • Selective reloads are performed with c4d.plugins.ReloadPythonPlugin()
      • ReloadDocumentAfterReload(True) is called only once after the reload batch

      Before reloading, the manager copies and normalizes the target file paths instead of retaining BasePlugin objects that may become invalid during the reload process. The manager itself remains visible in the list but cannot be selected or reloaded.

      Compatibility:

      • Current target: Cinema 4D 2026.3.3
      • Selective reloading depends on c4d.plugins.ReloadPythonPlugin, available in this version
      • Other Cinema 4D versions have not yet been verified
        2d3c073d-21ea-4e6f-8bba-4a84aee4c964-Anlv_2026-07-27_14-40-53.png

      Version: 1.3.0
      Plugin ID: 1069486
      Author: Anlv
      Download: Plugin Debug Manager v1.3.0.zip

      By the way, this is open source, and you can edit and modify it yourself to make it better suit your work habits.

      Best regards,
      Anlv

      posted in General Talk plugin-information download programming
      AnlvA
      Anlv
    • RE: Mesh Emitter CallCommand works in Script Manager, no-op from plugin

      Hi, @atg Simply remove the invalid child IDs after the commands recorded in the script log, for example:

      c4d.CallCommand(1062577, 1067510) → c4d.CallCommand(1062577)
      

      I remember encountering the same issue before, but I can’t quite recall the details. I need to look it up.

      import c4d
      
      doc: c4d.documents.BaseDocument  # The currently active document.
      op: c4d.BaseObject | None  # The primary selected object in `doc`. Can be `None`.
      
      def main() -> None:
          """Called by Cinema 4D when the script is being executed.
          """
          c4d.CallCommand(1062577)  # Mesh Emitter
      
      if __name__ == '__main__':
          main()
      

      How do I retrieve a command call from it's index number ?

      Cheers,
      Anlv

      posted in Cinema 4D SDK
      AnlvA
      Anlv
    • RE: Disable all animation in document

      @ceen Hi, The Summary row mey only a UI aggregate; it is not a single CTrack that can be switched directly.
      To reproduce its Animation switch, collect the real CTrack objects and set their c4d.ID_CTRACK_ANIMOFF value:

      # True = animation enabled, False = animation disabled
      track[c4d.ID_CTRACK_ANIMOFF] = False
      

      This does not delete keyframes and does not hide Timeline rows. Do not use NBIT_TLx_HIDE for this, because those flags only hide rows in the Timeline.
      A complete document-wide solution must also traverse Motion Sources in doc.GetNLARoot() . Add Motion Source moves/copies animation into that separate NLA hierarchy, so iterating only normal scene objects and tags will miss tracks such as Time and 2D Tracks.

      It should be noted that doc.GetNLARoot() is marked as Private in the SDK, and I'm not sure whether it should be used.

      """Toggle the Summary Animation switch for all collected CTracks."""
      
      import c4d
      
      
      def iter_nodes(node):
          while node:
              yield node
              yield from iter_nodes(node.GetDown())
              node = node.GetNext()
      
      
      def main():
          doc = c4d.documents.GetActiveDocument()
          tracks, seen = [], set()
      
          def add_tracks(owner):
              for track in (owner.GetCTracks() or []) if owner else []:
                  if id(track) not in seen:
                      seen.add(id(track))
                      tracks.append(track)
      
          def add_tree(root, include_tags=False):
              for node in iter_nodes(root):
                  add_tracks(node)
                  if include_tags:
                      for tag in node.GetTags() or []:
                          add_tracks(tag)
      
          add_tracks(doc)
          add_tree(doc.GetFirstObject(), include_tags=True)
      
          material = doc.GetFirstMaterial()
          while material:
              add_tracks(material)
              add_tree(material.GetFirstShader())
              material = material.GetNext()
      
          render_data = doc.GetFirstRenderData()
          while render_data:
              add_tracks(render_data)
              video_post = render_data.GetFirstVideoPost()
              while video_post:
                  add_tracks(video_post)
                  video_post = video_post.GetNext()
              render_data = render_data.GetNext()
      
          layer_root = doc.GetLayerObjectRoot()
          add_tree(layer_root.GetDown() if layer_root else None)
      
          # Private API, but required for Add Motion Source tracks in C4D 2026.
          add_tree(doc.GetNLARoot().GetDown(), include_tags=True)
      
          enabled = any(track[c4d.ID_CTRACK_ANIMOFF] for track in tracks)
          for track in tracks:
              track[c4d.ID_CTRACK_ANIMOFF] = not enabled
          c4d.EventAdd()
      
      
      if __name__ == "__main__":
          main()
      

      Cheers,
      Anlv

      posted in Cinema 4D SDK
      AnlvA
      Anlv

    Latest posts made by Anlv

    • RE: MergeDocument() crash C4D

      Hi, @chuanzhen

      I tested the same code as you in both saved projects and unsaved new documents, but no crash occurred. This might be a bug, possibly related to the ObjectData plugin in your project. I can't be certain that's the cause. You could try ruling out the plugin's influence first. But this is beyond my capability, so let's wait for more professional personnel to help.

      Cheers,
      Anlv

      posted in Cinema 4D SDK
      AnlvA
      Anlv
    • RE: MergeDocument() crash C4D

      Hi, @chuanzhen

      This code runs fine on my end (Cinema 4D 2026.3.4). Analyzing the cause of the failure may require more detailed information, such as the Cinema 4D version number and the real path (path resolution may occur), and corruption of the path_str file is also one possibility.

      Cheers,
      Anlv

      posted in Cinema 4D SDK
      AnlvA
      Anlv
    • RE: Disable all animation in document

      Hi @ferdinand,

      using the mxutils.RecurseGraph method is much clearer and simpler. Thank you, I've learned something new again.

      Cheers,
      Anlv

      posted in Cinema 4D SDK
      AnlvA
      Anlv
    • RE: Disable all animation in document

      @ceen Hi, The Summary row mey only a UI aggregate; it is not a single CTrack that can be switched directly.
      To reproduce its Animation switch, collect the real CTrack objects and set their c4d.ID_CTRACK_ANIMOFF value:

      # True = animation enabled, False = animation disabled
      track[c4d.ID_CTRACK_ANIMOFF] = False
      

      This does not delete keyframes and does not hide Timeline rows. Do not use NBIT_TLx_HIDE for this, because those flags only hide rows in the Timeline.
      A complete document-wide solution must also traverse Motion Sources in doc.GetNLARoot() . Add Motion Source moves/copies animation into that separate NLA hierarchy, so iterating only normal scene objects and tags will miss tracks such as Time and 2D Tracks.

      It should be noted that doc.GetNLARoot() is marked as Private in the SDK, and I'm not sure whether it should be used.

      """Toggle the Summary Animation switch for all collected CTracks."""
      
      import c4d
      
      
      def iter_nodes(node):
          while node:
              yield node
              yield from iter_nodes(node.GetDown())
              node = node.GetNext()
      
      
      def main():
          doc = c4d.documents.GetActiveDocument()
          tracks, seen = [], set()
      
          def add_tracks(owner):
              for track in (owner.GetCTracks() or []) if owner else []:
                  if id(track) not in seen:
                      seen.add(id(track))
                      tracks.append(track)
      
          def add_tree(root, include_tags=False):
              for node in iter_nodes(root):
                  add_tracks(node)
                  if include_tags:
                      for tag in node.GetTags() or []:
                          add_tracks(tag)
      
          add_tracks(doc)
          add_tree(doc.GetFirstObject(), include_tags=True)
      
          material = doc.GetFirstMaterial()
          while material:
              add_tracks(material)
              add_tree(material.GetFirstShader())
              material = material.GetNext()
      
          render_data = doc.GetFirstRenderData()
          while render_data:
              add_tracks(render_data)
              video_post = render_data.GetFirstVideoPost()
              while video_post:
                  add_tracks(video_post)
                  video_post = video_post.GetNext()
              render_data = render_data.GetNext()
      
          layer_root = doc.GetLayerObjectRoot()
          add_tree(layer_root.GetDown() if layer_root else None)
      
          # Private API, but required for Add Motion Source tracks in C4D 2026.
          add_tree(doc.GetNLARoot().GetDown(), include_tags=True)
      
          enabled = any(track[c4d.ID_CTRACK_ANIMOFF] for track in tracks)
          for track in tracks:
              track[c4d.ID_CTRACK_ANIMOFF] = not enabled
          c4d.EventAdd()
      
      
      if __name__ == "__main__":
          main()
      

      Cheers,
      Anlv

      posted in Cinema 4D SDK
      AnlvA
      Anlv
    • RE: Using SetWeightMap() multiple times can lead to inexplicable changes in weight values

      This appears to be a Float32-to-quantized-weight conversion or rounding issue in SetWeightMap(), rather than ordinary floating-point noise.

      Cinema 4D version: 2026.3.4
      Expected: unchanged values after every round-trip.
      Round  0: weight=0.14285496299687189 (14.28549630%), total=0.99998474097810308 (99.99847410%)
      Round  1: weight=0.1428397039749752 (14.28397040%), total=0.99987792782482621 (99.98779278%)
      Round 10: weight=0.14270237277790493 (14.27023728%), total=0.99891660944533434 (99.89166094%)
      Round 19: weight=0.14256504158083466 (14.25650416%), total=0.99795529106584246 (99.79552911%)
      Round 20: weight=0.14256504158083466 (14.25650416%), total=0.99795529106584246 (99.79552911%)
      Round 25: weight=0.14256504158083466 (14.25650416%), total=0.99795529106584246 (99.79552911%)
      
      posted in Cinema 4D SDK
      AnlvA
      Anlv
    • RE: Mesh Emitter CallCommand works in Script Manager, no-op from plugin

      Hi, @atg Simply remove the invalid child IDs after the commands recorded in the script log, for example:

      c4d.CallCommand(1062577, 1067510) → c4d.CallCommand(1062577)
      

      I remember encountering the same issue before, but I can’t quite recall the details. I need to look it up.

      import c4d
      
      doc: c4d.documents.BaseDocument  # The currently active document.
      op: c4d.BaseObject | None  # The primary selected object in `doc`. Can be `None`.
      
      def main() -> None:
          """Called by Cinema 4D when the script is being executed.
          """
          c4d.CallCommand(1062577)  # Mesh Emitter
      
      if __name__ == '__main__':
          main()
      

      How do I retrieve a command call from it's index number ?

      Cheers,
      Anlv

      posted in Cinema 4D SDK
      AnlvA
      Anlv
    • RE: [Free Plugin]Plugin Debug Manager v1.3.0— Python Plugin Reloading for Cinema 4D

      @ferdinand Thank you so much!
      I made some minor adjustments to the plugin, adding support for CTRL hotkey activation, which allows quick reloading of previously checked plugins that need to be reloaded without opening the window. As always, open source, and will continue to be open source.
      Download: Plugin Debug Manager v1.5.0.zip
      Cheers,
      Anlv

      posted in General Talk
      AnlvA
      Anlv
    • [Free Plugin]Plugin Debug Manager v1.3.0— Python Plugin Reloading for Cinema 4D

      Hi everyone, I’m releasing Plugin Debug Manager, a debugging utility for Cinema 4D Python plugin development.

      When working on a .pyp plugin, changing a single entry file can otherwise require reloading every Python plugin—or restarting Cinema 4D. Plugin Debug Manager reads the currently registered Python plugins and lets developers reload only the entries they are testing.

      Main features:

      • Reads registered .pyp and .pypv plugins from Cinema 4D
      • Groups multiple registrations by their actual entry-file path
      • Displays plugin names, icons, decimal IDs, registration types, and full paths
      • Filters entries by filename or plugin ID
      • Reloads one plugin, selected plugins, or all reloadable plugins
      • Supports click-and-drag checkbox painting for batch selection
      • Persists checked entries and can move them to the top on demand
      • Provides Reload Plugin, Reload All, Fold All, and Unfold All context commands
      • Locates plugin files in Explorer or Finder through c4d.storage.ShowInFinder()
      • Continues processing when an individual plugin fails to reload

      Implementation details:

      • Registry entries are collected with c4d.plugins.FilterPluginList(c4d.PLUGINTYPE_ANY, True)
      • Entry files and registration metadata are obtained through BasePlugin.GetFilename(), GetID(), and GetType()
      • Selective reloads are performed with c4d.plugins.ReloadPythonPlugin()
      • ReloadDocumentAfterReload(True) is called only once after the reload batch

      Before reloading, the manager copies and normalizes the target file paths instead of retaining BasePlugin objects that may become invalid during the reload process. The manager itself remains visible in the list but cannot be selected or reloaded.

      Compatibility:

      • Current target: Cinema 4D 2026.3.3
      • Selective reloading depends on c4d.plugins.ReloadPythonPlugin, available in this version
      • Other Cinema 4D versions have not yet been verified
        2d3c073d-21ea-4e6f-8bba-4a84aee4c964-Anlv_2026-07-27_14-40-53.png

      Version: 1.3.0
      Plugin ID: 1069486
      Author: Anlv
      Download: Plugin Debug Manager v1.3.0.zip

      By the way, this is open source, and you can edit and modify it yourself to make it better suit your work habits.

      Best regards,
      Anlv

      posted in General Talk plugin-information download programming
      AnlvA
      Anlv
    • RE: Problem with Undo when using COLOR field in a description resource

      @ferdinand Hi, I think the issue has been fixed. I just tried uploading an attachment (before uploading, I cleared the cache and changed the network environment), and it no longer prompts "Error: Something went wrong while parsing server response."

      Thanks for your help,
      Anlv

      posted in Bugs
      AnlvA
      Anlv
    • RE: Problem with Undo when using COLOR field in a description resource

      @ferdinand A small update:

      My first attempt to open the upload endpoint directly only returned Forbidden and did not display a visible Cloudflare verification page.

      I then used a small userscript to submit a real multipart file upload as a top-level browser navigation instead of an XHR request. That request succeeded and returned the normal NodeBB JSON response:

      {"status":{"code":"ok","message":"OK"}}
      

      More importantly, after this top-level request, the forum’s normal attachment uploader also started working successfully.

      This suggests that the top-level request allowed Cloudflare to complete or refresh its verification/clearance state, while the original XHR upload could not handle the HTML Challenge response. It appears to be a Cloudflare Challenge/clearance issue rather than a damaged file or a failure in NodeBB’s upload handler.

      posted in Bugs
      AnlvA
      Anlv