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
    • Unread
    • Recent
    • Tags
    • Users
    • Login
    1. Maxon Developers Forum
    2. Popular
    Log in to post
    • All Time
    • Day
    • Week
    • Month
    • All Topics
    • New Topics
    • Watched Topics
    • Unreplied Topics
    • All categories
    • S

      Python tag or Python node in Xpresso crash Cinema 4D

      Cinema 4D SDK
      • python 2026 windows • • SmetK
      5
      0
      Votes
      5
      Posts
      49
      Views

      S

      @ferdinand I just now noticed that the file attached incorrectly. At the time of publication, it's 6:00 PM(time of crash cinema 5:57PM), October 18th, Vladivostok time (UTC+10 (GMT+10)). The program crashes on random seed values. Am I correct in understanding that I can't change material parameter values ​​using the Python tag?
      _BugReport.txt

    • P

      Setting Preferences via script

      Cinema 4D SDK
      • python 2025 2026 • • pyr
      5
      0
      Votes
      5
      Posts
      64
      Views

      ferdinandF

      Hello @CJtheTiger,

      I am not quite sure how your question is meant, and generally new questions should constitute new topics.

      When you are asking, if when there is an ID_FOO: int = 12345 in V1, if we then just silently switch out the numeric value to ID_FOO: int = 54321 in V2, then the answer is sort of yesn't.

      We try to keep identifiers persistent. And for things like plugin IDs this is true without ifs and buts. I.e., once Ocube: int = 5159 has been defined, it will stay like this. But parameter values, e.g., PRIM_CUBE_LEN: int = 1100, can technically change. The goal is also to keep them persistent but in ABI breaking releases we sometimes have to modify descriptions. That is why we recommend that you always use symbols and not numbers.

      Cheers,
      Ferdinand

    • B

      Several Asset Browser Issues

      Cinema 4D SDK
      • 2026 2025 python • • blkmsk
      4
      0
      Votes
      4
      Posts
      44
      Views

      ferdinandF

      Hey @blkmsk,

      I did not say that your posting was messy 😉 I of course understand that one sometimes can get a bit overwhelmed when in the middle of things, and that it is then quite hard to be super organized. As I said, it was clearly visible that you put effort into this.

      Regarding your bug isssue. In general, I do not like interfering too much with other devs work, and something in our bug tracker being marked as fixed, does not necessarily mean that it will make it into a release. But I pulled up your bug issue #604301 and there is long discussion between devs and QAs going on. Our build system made a comment roughly 72 hours ago, that a fix has been submitted, and shortly after that that is has been fixed (i.e., the build suceeded).

      This is however only a fix, not a verified fix (i.e., no QA has yet confirmed that what the devs came up with actually fixes the problem), it could still be rolled back. For details you better talk with end user support when this is urgent for you. Alin from end user supports seems to have handeled this.

      Cheers,
      Ferdinand

    • JH23J

      Editable Object Plugin returns Null after scaling

      Cinema 4D SDK
      • python • • JH23
      4
      0
      Votes
      4
      Posts
      78
      Views

      ferdinandF

      Hey @JH23,

      there is no need to apologize for a lack of context. Now that I read your first posting again, it is actually perfectly clear what you are asking for. I just did not read it properly, my bad, sometimes this happens when I am in a hurry.

      The answer to your question is not trivial, but the TLDR is that you have only little control over it.

      There exist two commands, 'Current State to Object' (CSTO) and 'Make Editable' (ME). CSTO is basically the less aggressive version of ME, where it runs through all the elements of a cache of something and tries to collapse them gracefully (which could result in output that is still collapsible itself). ME more aggressively flattens the cache hierarchy.

      For both commands, at the very basic level, there is the distinction between generators and and non-generators. When you CSTO some generator object which just holds another generator in its cache (imagine your GetVirtualObjects or main just returning c4d.BaseObject(c4d.Ocube)), it will just return a copy of that generator (which is still a generator, i.e., something that has a cache). But when your generator returns a non-generator, i.e., a discrete PolygonObject, it will wrap the copy of this cache in a null when returning it.

      But that is not all of it. Because, there are also functions such as TransferDynamicProperties and OptimizeHierarchy which ensure that relevant scene data is kept and the output is as compact as possible. They run after ME/CSTO by further manipulating the ME/CSTO output. The original MEed/CSTOed object might have had a transform which must be copied onto the flattened output, so that it has the same transform in world space. Objects often also hold hidden data in form of tags in Cinema 4D which might have to be copied from the original object onto the flattened result. This all might lead to the functions either removing unnecessary null objects which before have been created by ME/CSTO or adding new ones.

      That your scale manipulations result in an extra null is a bit surprising, but that must have to do with the transform normalization code which runs after ME/CSTO. At first I thought, it might transfer the scale to the null object, so that it can normalize the scale of the cache. But that is not the case, it is still the cache object which has the scale 2 when you CSTO/ME your generator. I would really have to debug this in detail, to find out why exactly this happens.

      But in general, I would advise against scaling the matrix/transform of an object, and instead, apply the scale to the points of a discrete PolygonObject or the parameters of a BaseObject itself. Transforms which have axis components of non-unit length (i.e., a scale != 1.0), often lead to problems.

      The important message is that even when you find a solution which gives you the desired flat cache for this problem (by for example scaling the points), there could be countless other scenarios such as a user having a MoGraph tag on your generator or something like that, where then MEing or CSTOing would result in a null + cache output. You should not build your code on the assumption that the MEed or CSTOed output of your generator will always be flat (or the opposite), because you simply cannot guarantee that.

      Not the most satisfying answer, I know, but I hope it helps to clarify the situation.

      Cheers,
      Ferdinand

      Here is how you could post process points with a transform:

      def main(): obj: c4d.PointObject = Cube() # We could of course also just pass this #transform into your #Cube function, to do it right # there. But we are making a point of doing this as a post processing step (so that we can do # this at any point in time). We scale all points by a factor of 2 and rotate them 45° on the # Y axis in the coordinate system of the object. When we now CTSO your object, we have a flat # output. transform: c4d.Matrix = (c4d.utils.MatrixScale(c4d.Vector(2, 2, 2)) * c4d.utils.MatrixRotY(c4d.utils.DegToRad(45))) obj.SetAllPoints([n * transform for n in obj.GetAllPoints()]) obj.Message(c4d.MSG_UPDATE) return obj
    • lasselauchL

      Plugin module import freezes on startup

      Cinema 4D SDK
      • python macos windows 2026 2025 • • lasselauch
      4
      1
      Votes
      4
      Posts
      108
      Views

      ferdinandF

      Hey Jacob,

      Thank you for the added data. First of all, I have invited you to the forum to end this middle man communication, which is a bit odd.

      The pyz file is part of python ...

      I am aware of what pyz is, I just pointed this out because I of course looked inside your package and found all the py_armor obfuscated code and the injected binaries in there. So, I pointed out that this is bit more than just "packaged in a pyz file for ease of distribution [...]" as Lasse/you put it, the goal is here clearly obfuscation. Which is also relevant for support, as it limits what you and I can see (without getting hacky).

      My finding with the 10mb file freeze comes from my trial and error ... mean[t] when you run a script from Extensions -> User Scripts.

      Your code also freezes when you load it as a Script Manager script. That is what I did with the last package from Lasse, and now also yours. The code in your script is again wrong, which is why it won't freeze until you fix it. This is the code I found:

      2bd4290e-78b2-43d4-936d-1e2a7eaf366b-image.png

      And I fixed it then to this. When I ran it then, Cinema 4D froze for two minutes or so, after that it opened a myriad of dialogs to then terminate into two crash dialogs (it was pure luck that I let it run for so long, Lasses previous version might have acted similar, but there I killed the C4D process, as soon as I saw the 'beach ball of death' cursor on MacOS).

      69fcb5da-ac49-477e-8f70-9daeb1daa1aa-image.png

      ⚠ Please read my answer below carefully, as I already pointed out most of this in my previous posting.

      I would STRONGLY suggest debugging this without obfuscation. Maxon also cannot debug larger sections of code or test further packages for you. I understand that obfuscation might not be your choice, but it will make your life harder in debugging this, as you always fly blind. We of course still will provide support, but you have to provide more than "it does not work/crashes/freezes, please help us", especially when this is not code tied to our APIs. Attach a debugger from the Script Manager and see why your code crashes/freezes (see link in last posting when unsure how to do this). But you need an un-obfuscated code base for this to make any sense. Defer your loading to a later point, e.g., C4DPL_PROGRAM_STARTED, when you have issues in the direct plugin registration context. In that case you would always register your plugin, but then only execute it when the your own license check succeeded. But you absolutely cannot ship a plugin which freezes Cinema 4D for multiple minutes on startup or when invoking your plugin because your licensing takes so long. When we see this in the wild, we will have to blacklist your plugin IDs, as this damages the brand Cinema 4D. Please use threading then to not block the main thread with your long running code. What I did not notice before is that you apparently try to open multiple dialogs (for me it opened multiple dialogs when I ran the script). The GUI and many other systems are not yet available when Cinema 4D is still booting, e.g., in the splash screen. You can expect all systems to be up and running when C4DPL_STARTACTIVITY is emitted, but it is better to wait for C4DPL_PROGRAM_STARTED for long running tasks (i.e., the two events I tested in my previous posting). Please also keep in mind that Cinema 4D has its own anti-piracy measures. Python plugins are sort of special in that they work slightly different than native C++ plugin modules (the Python C++ module shipped by Maxon sort of acts as a surrogate for Python plugins in the module registration phase). But Cinema 4D won't allow plugin threads to start their own processes at this point (which you might be trying to do with your injected binaries), and threading should also be avoided at this point, as the job system of Cinema 4D might be still booting. What you are meant to do in PluginStart (or the __main__ context of a pyp file), is register your plugins. You can run some quick logic there, but you are certainly not meant to start communicating with servers and opening GUIs there. You can read here a bit more about this from a C++ system perspective. I would recommend to do your license check in the background in its own thread once C4DPL_PROGRAM_STARTED has been emitted (so that you can also open dialogs to signal errors). An alternative would be to do it when the user clicks the button of your command. But you should also here put it into its own thread, so that it does not block everything else.

      Cheers,
      Ferdinand

    • E

      Document copied for Picture viewer doesnt copy contents of child of a TagData

      Cinema 4D SDK
      • c++ • • ECHekman
      4
      0
      Votes
      4
      Posts
      93
      Views

      ferdinandF

      Hello @ECHekman,

      Thanks for providing the information that the init function should not modify the scene graph. Ill take this into account in the future.

      It is not only NodeData::Init but the majority of NodeData methods and the methods of derived classes that cannot modify the scene graph of a loaded document, as for example the scene graph they are attached to. The reason is that such methods, as for example NodeData::Init, TagData:Execute, ObjectData::GetVirtualObjects, and many more, run in their own threads to parallelize scene execution. Modifying the scene graph of a loaded document from a non-main-thread (i.e., parallel) context can lead to race conditions and access violations and are therefore strictly forbidden. Forbidden are primarily allocations and deallocations, parameter get/set access is allowed (as long as it does not allocate or deallocate a pointed object) but also discouraged outside of TagData::Execute. For details, see Cinema 4D Threads Manual.

      I went through that example you linked, but I' m a bit unclear why it is necessary to manually create the handling of a custom and parallel nodegraph branch when plugin GeListNodes are already graphs themselves?

      I am not quite sure how you mean 'parallel', but a GeListNode implements both hierarchal (i.e., tree) relations with InsertUnder, GetUp, GetDown, GetNext etc. and arbitrary (i.e., graph) relations with GetBranchInfo. The hierarchy of a node type, e.g., Obase - a BaseObject or Tmytag - your tag class, are always meant to be of the same type and follow the conventions of their base class. Tags are not meant to have children. You must implement your own branch to declare your own non-hierarchical relation between your plugin tag and your basic node.

      ⚠ The workaround Maxime suggested, just implementing NodeData::CopyTo is unfortunately not valid.

      First of all, you must always implement all three serialization functions Read, Write, and CopyTo, you can never only implement only one of them.

      But storing nodes irregularly in this manner can lead to access violations as Cinema 4D is then not aware that this quasi-branch exists and might try to execute multiple things at once (via NodeData::GetAccessedObjects), leading to read/write access violations. Moreover, I am fairly sure that this might lead to event or call starvation when Cinema finds there such a dangling BaseList2D (NodeData) instance under your BaseTag (TagData). Or even worse, it will ignore completely it in some contexts, because tags are not supposed to have children.

      You must implement a branch in your case, I would recommend following the SDK example as it is slightly cleaner than the forum preview Maxime linked to.

      Cheers,
      Ferdinand

    • gheyretG

      Determine object category (Generator, Deformer, etc.) via Python

      Cinema 4D SDK
      • python 2026 2025 • • gheyret
      3
      0
      Votes
      3
      Posts
      77
      Views

      gheyretG

      Thank you for the C++ code—it's been very helpful!
      Cheers!

    • R

      Set VERTEXCOLOR in PaintTool

      Cinema 4D SDK
      • python r25 windows • • randymills
      3
      0
      Votes
      3
      Posts
      84
      Views

      R

      @m_adam Thank you so much for the help, that works perfectly and thank you for showing me both methods, that's very helpful and appreciated!

    • Viktor VelickoV

      Forcing GetDDescription() refresh in ToolData plugin (EventAdd not working)

      Cinema 4D SDK
      • c++ • • Viktor Velicko
      3
      0
      Votes
      3
      Posts
      94
      Views

      Viktor VelickoV

      Thank you, Maxim.
      No further testing is needed—this works very well.
      I’m calling it from the ToolData::MouseInput() callback at the end, which is sufficient. The panel updates nicely after the mouse event finishes (on mouse up).

      SendCoreMessage(COREMSG_CINEMA, BaseContainer(COREMSG_CINEMA_FORCE_AM_UPDATE));
      GeUpdateUI();

      You can close this thread.
      Thanks!
      V.

    • CJtheTigerC

      C4D Prototype To Plugin Converter -> Where did it go?

      General Talk
      • programming plugin-information • • CJtheTiger
      2
      0
      Votes
      2
      Posts
      15
      Views

      ferdinandF

      Hey @CJtheTiger,

      Thank you for reaching out to us. That seems to be part of what the Cinversity team did before I joined Maxon. This was never a project of the SDK team. And more over, this seems to have been a private project of Niklas Rosenstein, an ex Maxon employe, because the link points to his GitHub. Niklas is still on GitHub, maybe you can send him a message if he still has his old code? But this looks like an R25 or even older project, so this will for sure require some update work.

      There are also the Cinversity legacy downloads on Maxon's downloads page, but it does not seem to contain it either.

      Cheers,
      Ferdinand

    • P

      Feedback on C4D Plugin – Mapping Textures to a Pixel Grid (Cinema 4D 2024 SDK)

      Cinema 4D SDK
      • s24 c++ 2024 windows • • Pheolix
      2
      0
      Votes
      2
      Posts
      67
      Views

      ferdinandF

      Hey @Pheolix,

      Welcome to the Maxon developers forum and its community, it is great to have you with us!

      Getting Started

      Before creating your next postings, we would recommend making yourself accustomed with our forum and support procedures. You did not do anything wrong, we point all new users to these rules.

      Forum Overview: Provides a broad overview of the fundamental structure and rules of this forum, such as the purpose of the different sub-forums or the fact that we will ban users who engage in hate speech or harassment. Support Procedures: Provides a more in detail overview of how we provide technical support for APIs here. This topic will tell you how to ask good questions and limits of our technical support. Forum Features: Provides an overview of the technical features of this forum, such as Markdown markup or file uploads.

      It is strongly recommended to read the first two topics carefully, especially the section Support Procedures: How to Ask Questions.

      About your First Question

      Your code looks generally good, especially for someone who is starting out with the API you did really well. With that being said, I do not really understand what you want to do:

      ... plugin that maps and arranges textures onto a pixel grid. The goal is to make it easier to create voxel-style or Minecraft-like models by linking real-world units (e.g., centimeters) to pixels. (for example, 1 pixel = 6.25 cm)

      A few pointers:

      A CommandData plugin is the perfect choice when you want to manipulate the scene without any restrictions and are fine with always having to press a button run your logic. Scene element plugins, e.g., objects, tags, etc. on the other hand will carry out their logic on their own when a scene update is invoked. But they come with the restriction that their major payload functions (ObjectData::Execucte, ObjectData::GetVirtualObjects, TagData::Execute, etc.) run in their own threads (so that scene execution is parallelized) and therefore are subject to threading restrictions (I am aware that you are on C++, but the Python docs are better on this subject). So, for example, in a TagData::Execute you would not be allowed to allocate a new UVW tag on the object that is also hosting your plugin tag. But you could implement a button in the description of the tag, which when clicked cerates your setup (because TagData::Message runs on the main thread and you therefore are there allowed to add and remove scene data). With TagData:Execute you could then continuously update the UVW tag you are targeting on each scene update (changing parameter values of other scene elements is fine when tags are executed). This workflow is not necessarily better than a command, I am just showing you an option. Commands are also easier to implement for beginners than a scene element. When you talk about units, you should be aware that both the object and texture coordinate system are unitless. What you see in edit fields, is just smoke and mirrors. We recently talked here about this subject. You did get the major gist of our error handling but what you do with maxon::Failed is not quite correct. It is meant to test the return value of a Result<T> for having returned an error instance instead of T. When you want to indicate an error, you must return an error, e.g.,: // Not correct. if (!doc || !selectedObject || !bitmap || !foundTag) return maxon::FAILED;T // This is how one indicates that a function failed because something was a nullptr. if (!doc || !selectedObject || !bitmap || !foundTag) return maxon::NullptrError(MAXON_SOURCE_LOCATION, "Could not get hold of scene data."_s); // For a function which is of type Result<void>, its also totally fine to do this on an error. void functions // can fail successfully, it is up to you to decide if an error is critical enough to halt execution of if you just // want it to silently terminate. if (!doc || !selectedObject || !bitmap || !foundTag) return maxon::OK; // we are okay with failing here.

      For details see Error handling and Error Types

      Cheers,
      Ferdinand

    • aghiad322A

      Ctr+drag copy vs internal copy in CopyTo function in C++

      General Talk
      • plugin-information • • aghiad322
      1
      0
      Votes
      1
      Posts
      11
      Views

      No one has replied