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. ferdinand
    3. Posts
    • Profile
    • Following 0
    • Followers 15
    • Topics 54
    • Posts 3,105
    • Best 755
    • Controversial 1
    • Groups 2

    Posts made by ferdinand

    • RE: The value of 'porgress' during the use of RenderDocument() is greater than 1.0

      Hey @chuanzhen,

      Thank you for reaching out to us. I will have a look at this problem, at the latest by the end of next week (31/10). We are aware that RendeDocument keeps regressing, because there are a lot of render technology changes happening behind the scenes in the Cinema in the last releases.

      Hopefully, this is just a smaller bug, or a user error. But this could also be a more complicated thing. I will let you know at the latest by the end of next week.

      Cheers,
      Ferdinand

      posted in Cinema 4D SDK
      ferdinandF
      ferdinand
    • RE: Ctr+drag copy vs internal copy in CopyTo function in C++

      Hey @aghiad322,

      Thank you for your reply. NodeData::Init is always being called when a node is initialized, explicitly also when a node is being copied (that is what the argument isCloneInit is for). But scene hooks only very rarely get copied since they are effectively singletons.

      All I can tell you from your description, is that what you are doing in general - "have a scenehook and it has an array member variable pointing to all tags in the scene with this tag type", sounds like a bad idea. It sounds like you have a BaseArray<BaseTag*> - or even worse, a std::vector<BaseTag*> - on your scene hook as a field; and this is just asking for crashes. You must use either smart pointers (BaseArray<WeakRawPointer<const BaseTag>>) or BaseLink's. But even then this is not such a great idea, your scene hook should gather its inputs each time it needs them. And when you end up constantly scanning the scene, you are doing something wrong design-wise. There are niche scenarios where this cannot be avoided, but I cannot really evaluate that if I have absolutely no idea what you are doing.

      As already lined out, we cannot help you if you do not show us what you are doing. You are likely talking about your tags being copied, but you do not show us if you implement the tag yourself, what your code is, and what you are trying to achieve in general. How are we supposed to help you, when you do not tell us/show us what you are doing?

      Cheers,
      Ferdinand

      posted in General Talk
      ferdinandF
      ferdinand
    • RE: Python tag or Python node in Xpresso crash Cinema 4D

      Hey @SmetK,

      Thank you for the reproduction steps, this makes it much easier for us. The added information is that you must play back the timeline. I am, however, still unable to reproduce your crash. But I am still using on Windows a very late beta version of the 2026.0.0 RC, I will try to squeeze in some time this week to install the actual customer RC. I also checked macOS, where I have already 2026_0_0_db12fb68d6ba_2004155263 installed, i.e., your build, and the build the crash report was resolved for, and nothing is crashing there either.

      I also had a look at your scene setup and all in all this is all very tame, especially Python-wise; this should not crash. What is a bit iffy, is that you use both a Python tag and a (Python) Xpresso setup to set scene parameters, and have them both set to the same priority. But the worst this should be able to lead to is race conditions. But since you seem to be able to reproduce this reliably, while we cannot, I would ask you to:

      1. Test if this also crashes when you (a) disable the Python tag, (b) disable the Python tag AND the Xpresso tag, and (c) if it still crashes if you only disable the Xpresso tag.
      2. Test if this still crashes if your make the priority of the Python and Xpresso tag more verbose, i.e., set your Python tag to something like this:

      74db7781-44d4-495c-b328-8aca94233229-image.png

      Overall, this does not strike me as something that is Python induced, as all you do is set parameters.

      Cheers,
      Ferdinand

      posted in Cinema 4D SDK
      ferdinandF
      ferdinand
    • RE: Python tag or Python node in Xpresso crash Cinema 4D

      Hey @SmetK,

      hm, weird, I could not find your submitted crash report. Neither when I search by date nor by Call_Stack_Thread_24992. But I did insert your crash report myself and below are the last lines of the stack trace for the crashing thread (this is being read bottom to top, i.e., SplitIntoNgons is where it crashed). I did resolve this for the build 2026_0_0_db12fb68d6ba_2004155263. Which is not unimportant information, as using a wrong build to resolve crash offsets can lead to wildly inaccurate results. You can find out the build you are using by opening the Help > About window and there right clicking the build number.

      Call_Stack_Thread_24992
          c4d_objects.xdl64 = maxon::boolean::OutlineSplitter::SplitIntoNgons
          c4d_objects.xdl64 = maxon::boolean::OutlineSplitter::SplitOutline
          c4d_objects.xdl64 = maxon::boolean::CutObject::<lambda_0>::operator()
          ... internal API gibberish, nothing semantically relevant here ...
          c4d_objects.xdl64 = maxon::boolean::PreProcessInput
          c4d_objects.xdl64 = cinema::BooleanGenerator::GetVirtualObjects
          c4d_base.xdl64 = cinema::PluginObject::GetVirtualObjectsNew
          c4d_base.xdl64 = cinema::BaseObject::CreateVirtualObjects
          ... (more lines) ...
      

      So, as already indicated by your bug_report.txt itself, this is crashing in one of major modules of Cinema 4D (c4d_objects.xdl64) and not one of our Python modules (python.xdl64 or python_vm.xdl64). So neither your direct Python code nor the Python VM are the culprit. But it could still be that you are indirectly causing the crash, by for example deleting a scene element off main thread. And SplitIntoNgons then tries to access that object and everything goes up in flames.

      The crash happens while trying to build the output of the new Boolean object. I briefly talked with the dev of the new Booleans, and he said he did not see crash stack trace yet, so this is not a known bug. It seems to choke on some n-gon input in particular. Maybe this does ring a bell for you, in the context of what you are doing?

      Your scene does not crash in my local Cinema 4D 2026.0 (Win) nor the one from the Booleans developer, are you sure you are using the most recent build? Maybe you could try to manually recrate one of your setups (i.e., without Python) and see if that crashes too? Without us being able to reproduce the crash, it will be impossible to help you. See our Support Procedures: Examples for how to report crashes in a more effective way.

      Cheers,
      Ferdinand

      posted in Cinema 4D SDK
      ferdinandF
      ferdinand
    • RE: Ctr+drag copy vs internal copy in CopyTo function in C++

      Hey @aghiad322,

      Thank you for reaching out to us. Your question is very hard to answer like this. Please familiarize yourself with out support procedures and what makes a good technical question. I have effectively no idea what you are doing.

      When you are talking about a NodeData::CopyTo call, its context is expressed in the flags, including if this was a clipboard event. I would assume that a drag and drop operation, especially for tags, does not entail the tag being copied, but actually rather be moved (i.e., being removed and then re-inserted). If it is being copied, or at least being copied in your case, I do not see how this should then be distinguished from an 'internal' call, since they are all 'internal'.

      I would just look at the flags and see if they change in a manner that is helpful for your task. Although what you are trying to do does not sound like a good idea, but I more or less know nothing about what you are doing and am guessing mostly.

      Cheers,
      Ferdinand

      posted in General Talk
      ferdinandF
      ferdinand
    • RE: Python tag or Python node in Xpresso crash Cinema 4D

      Just to be clear: I did not want to imply that we do not want to help you. But we need a little bit more from you. I would suggest to try to upload the crash report again. What is even better, is when you tell me a date and time (and your timezone) when you did submit a crash report (or a unqiue message you have put into the crash message).

      posted in Cinema 4D SDK
      ferdinandF
      ferdinand
    • RE: Several Asset Browser Issues

      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

      posted in Cinema 4D SDK
      ferdinandF
      ferdinand
    • RE: C4D Prototype To Plugin Converter -> Where did it go?

      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

      posted in General Talk
      ferdinandF
      ferdinand
    • RE: Python tag or Python node in Xpresso crash Cinema 4D

      Hello @SmetK,

      Thank you for reaching out to us. Your file is not crashing for me, and you did not actually include your crash report. Please follow our Support Procedures regarding reporting Bugs and Crashes.

      Please also note that this is actually reserved for bugs and crashes caused by our API and not by user code. It is of course not out of question that this is caused by a bug in our API, but by for example violating threading restrictions, your code could also be easily the culprit. Please also understand that we do not run a debugging service here, you cannot just give us your code and expect us to figure out where and why it crashes. We expect some form of work on your side which pinpoints the problem to: "When I do this, Cinema 4D crashes, why?".

      Cheers,
      Ferdinand

      posted in Cinema 4D SDK
      ferdinandF
      ferdinand
    • RE: Several Asset Browser Issues

      Hello @blkmsk,

      Thank you for reaching out to us. Please follow our Support Procedures. Your postings were violating multiples:

      • Singular Question: The initial posting of a support topic must contain a singular question. Do not ask ten things at once, that makes it extremely hard to answer topics. [...]
      • Singular Posting: Users often discover additional information or even a solution before we can answer. Please consolidate your questions into a singular posting by editing your last posting. [...]
      • Briefness: Your posting should explain in the first sentence where your problem lies. Avoid writing lengthy paragraphs about tangential subjects [...]
      • Repeatable: Your claims or problem should be repeatable for us. [...]

      Just to name a few. I have consolidated your postings, please read the support procedures guide for future postings. You do not have to follow it to the letter, but we should be all following its general spirit.

      About your questions

      It is not that I would not see that you have put effort into this, links and video recordings do not manifest out of thin air. But the current form unfortunately fails to convey relevant information for your second question.

      [...] I'm unable to export the latest version of one or more assets as a ZIP file through the asset browser since version 2025.3.1. The export seems to work fine but when I try to re-import the ZIP file via 'Create' -> 'Import Asset' in the asset browser I get a error message: fileformat[asset.impl.cpp(4541)]"

      That would be an end user bug because there is no code invloved, please report it via the support-center. Without an exact version the file and line number is not too much worth as our source code often changes drastically, even for minor version increments. But this is a call deep inside an internal system. I think it tries to resolve IDs in your zip there. Which could hint at your zip database being somehow malformed. But you have to discuss this with end user support.

      So I tried creating a new asset with a new asset id in version 2026. With this new asset the script is working in version 2026 but using it in previous version now again freezes Cinema 4D.

      This is all a bit hazy for me, better reproductions steps in accordance with our support guidelines would help here a lot. I watched your first video, and you seem to load some complex rig, and then run a Script Manager script, and then Cinema 4D freezes. But you seem to have also other Python code in your scene. This is pretty much all a black box for me and therefore very hard to answer.

      1. When you have problems with that zip database of yours, I would first make sure that this is not the same issue, i.e., make sure that whatever assets you try to load, are sourced from a non-tainted database. Ideally the built-in database.
      2. Event notifications are private for a reason and can easily be the cause for crashes. I think you used the toon rig in your videos and it unfortunately uses event notifications in its Python code. So, I guess you got it from there. But when you changed something about the toon rig or its code, this could lead to freezes. NOTIFY_EVENT_MESSAGE is however one of the more harmless event notifications and it is somehwhat unlikely that it is the cause.

      My recommendation would be to first sort out if your database is not somehow malformed. If that does not help, please show us your code and scene files, without them, we cannot help you. Please put some time into boiling down your issue. There are so many moving parts here such as your zip database, and that ultra complex toon rig. Ideally you show us something that fails with out builtin database in a simple scene.

      Cheers,
      Ferdinand

      posted in Cinema 4D SDK
      ferdinandF
      ferdinand
    • RE: RenderDocument produces different color

      Hey @moghurt,

      no, there is unfortunately not a permanent solution yet, we have talked about it, but nothing concrete has yet happened. But your verbatim statement that RenderDocument does not respect OCIO, is not true. It does, it just a bit complicated to serialize the linear render result into non-linear files on disk or to send them to the picture viewer.

      Check the Python SDK OCIO Examples for details.

      Cheers,
      Ferdinand

      posted in Bugs
      ferdinandF
      ferdinand
    • RE: Setting Preferences via script

      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

      posted in Cinema 4D SDK
      ferdinandF
      ferdinand
    • RE: Setting Preferences via script

      Hey @pyr,

      yes, that your own answer is correct, thank you for sharing it! But since 2026.0.0 there exist better ways to discover symbols and container values. Have a look at the mxutils change notes for 2026.0 for an overview.

      With g_c4d_symbol_translation_cache you can discover the symbol for a plugin ID such as 465001632 and with GetParameterTreeString you can inspect node parameters in a human readable form.

      Cheers,
      Ferdinand

      edit: Maxime pointed out that you could also call SaveWorldPreferences in anticipation of Cinema 4D crashing later on and therefore not saving your changes. I quite frankly think this is overkill and that you should not write code that expects that c4d will crash. But it is of course the safer option in a worst case scenario.

      posted in Cinema 4D SDK
      ferdinandF
      ferdinand
    • RE: Editable Object Plugin returns Null after scaling

      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
      
      posted in Cinema 4D SDK
      ferdinandF
      ferdinand
    • RE: Plugin module import freezes on startup

      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

      posted in Cinema 4D SDK
      ferdinandF
      ferdinand
    • RE: Editable Object Plugin returns Null after scaling

      Hello @JH23,

      Thank you for reaching out to us. Your code is looks correct, but you should not return None on a critical error (e.g., when you run out of memory to allocate things), but return c4d.BaseObject(c4d.Onull) instead, that is also what Cinema 4D will do, when it cannot make sense out of your method. E.g. it should be:

      if not(cube := c4d.BaseObject(c4d.Ocube)):
          return c4d.BaseObject(c4d.Onull)
      
      cube[c4d.ID_BASEOBJECT_REL_SCALE, c4d.VECTOR_X] = 2.0
      ...
      

      Also, does your object have child inputs it depends on? E.g., like an Extrude object which depends on a child spline? I assume it does not, right? You should then change your manual dirty check to this, because your code also tries to build the children of this node which could lead to issues.

      # Only build the cache of the object when one of its parameters has changed or when there is no cache.
      if not op.IsDirty(c4d.DIRTY_DATA) and op.GetCache():
          return op.GetCache() # you could also pass the hh here, but that is not necessary in this case
      

      Do you see any errors in the console when this happens? Cinema 4D returning a null object for a cache means that building the cache failed. There must be somewhere a bug in your code, I am not sure though that my suggestions will fix it.

      I would also like to know if there is a specific way to return several objects or a specific one when making the generator editable, making it more customizable.

      A cache must always terminate into a singular object because it is just part of an object hierarchy. When you want your cache to contain multiple things, you must parent them to a null and return that null as your cache.

      As to reacting to CTSO, yes that is possible, but not in Python. When an object is being built for CSTO, its HierachyHelp->GetFlags() will be BUILDFLAGS::EXTERNALRENDERER | BUILDFLAGS::ISOPARM but HierachyHelp has not been wrapped for Python. There is MSG_CURRENTSTATE_END emitted, and you can capture this in Python too via NodeData::Message, but that is only the signal that CSTO has finished (and that you might want to revert to a non-CSTO specialized cache).

      But in general, we advise against such trickery where objects switch out their cache in certain contexts. It is valid to do this, but often requires intimate knowledge of the API to be done sucessfully.

      Cheers,
      Ferdinand

      posted in Cinema 4D SDK
      ferdinandF
      ferdinand
    • RE: Plugin module import freezes on startup

      Hey @lasselauch,

      Thank you for reaching out to us. In general, your problem is simply out of scope of support, as you are trying to get the aescripts third-party library going.

      The license script is packaged in a pyz file for ease of distribution [...]

      That is not quite the truth, is it? The package is clearly zipped to further increase the obfuscation which happens with pyarmor inside and to hide away its injected binaries (in /aescripts_PythonLicenser/aescripts_PythonLicenser/bin). Which also explains the package size which is otherwise not obtainable with pure Python code.

      One problem we're facing is that for C4D plugins C4D gets stuck on startup when showing Initializing Plugins 100%. After a lot of trial and error I found out that this happens ONLY when the pyz file is bigger than ~10mb. This doesn't happen if you run a script that imports the pyz. Only for plugins that gets loaded on startup.

      1. You could easily defer the loading of your package when Cinema 4D and the size would be the culprit (but that is rather unlikely because Cinema 4D loads itself 100's of megabytes when the modules are loaded). But I went ahead and did it and deferred the loading to C4DPL_PROGRAM_STARTED (the latest point in the boot sequence, this is when the user sees the c4d UI for the first time) and also to C4DPL_STARTACTIVITY (a bit earlier, but after all modules have been loaded). See PluginMessage for details. This does not really change the outcome; it just freezes then at a later point, e.g., to the point when the user sees the UI.
      import os
      import sys
      import c4d
      
      lic_settings = {
          ...
      }
      
      def PluginMessage(id, data):
          if id==c4d.C4DPL_PROGRAM_STARTED:
              current_directory = os.path.dirname(os.path.abspath(__file__))
              pyz_path = os.path.join(current_directory, 'res', "aescripts_PythonLicenser.pyz")
              sys.path.insert(0, pyz_path)
              from aescripts_PythonLicenser import aesl
      
          return True
      
      1. I then had a look at your claim that 'this doesn't happen if you run a script that imports the pyz'. Your Demo_Script.py is faulty as it does not define the import path correctly, it is missing the 'res' directory and therefore only raises an import error. When you fix that, it just freezes as much as the other code (which is not very surprising since executing a Script Manager script and code after C4DPL_PROGRAM_STARTED are more or less the same thing).
      import sys
      import os
      
      # Must be os.path.join(dir, "res", "aescripts_PythonLicenser.pyz")
      sys.path.insert(
          0,
          os.path.join(
              os.path.dirname(os.path.abspath(__file__)), "aescripts_PythonLicenser.pyz"
          ),
      )
      from aescripts_PythonLicenser import (
          aesl,
          UpdateStatus,
          aesl_log,
          show_logs,
          run_license_tests,
      )
      

      Conclusion

      The TLDR is here that you have there an obfuscated library which seems to freeze in any context in Cinema 4D. This could either be a flat-out bug in your library where it never exits some loop or due to the library trying to use features that are not available in Cinema 4D (multiprocessing, tkinter, asyncio, etc.). I would recommend that you get an un-obfuscated version of the library, and then try to load it from a Script Manager script with a debugger attached, to see where it hangs.

      Also, py_armor and all the other things the aescripts library does will not deter any cracker. They will just crack your encrypted pyp file (which I assume you planned on doing), and remove the aescripts library. You cannot even make binary language (e.g. C++) executables crackproof, and for languages like Python, it is just a joke for anyone even remotely competent. py_armor is not a good idea. So, it stands to be questioned if all that effort is worth it. The most effective licensing system is a low effort server request for a valid user/serial number which keeps honest users honest. Crackers will remove that too, but then you have at least not poured days, weeks, or even months into a system which will be cracked within 72 hours after release.

      Cheers,
      Ferdinand

      posted in Cinema 4D SDK
      ferdinandF
      ferdinand
    • RE: Document copied for Picture viewer doesnt copy contents of child of a TagData

      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

      posted in Cinema 4D SDK
      ferdinandF
      ferdinand
    • RE: Feedback on C4D Plugin – Mapping Textures to a Pixel Grid (Cinema 4D 2024 SDK)

      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:

      1. 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.
      2. 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.
      3. 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

      posted in Cinema 4D SDK
      ferdinandF
      ferdinand
    • RE: exporting usd with python

      Hey @lionlion44,

      Thank you for reaching out to us. I doubt that this will not work in Python, it is just that we have not documented the symbols there yet. But you can find them in the C++ docs:

      6e23eada-2198-4c34-84bf-a576bbdd0ef9-image.png

      I.e., it will be c4d.FORMAT_USDIMPORT and c4d.FORMAT_USDEXPORT.

      Cheers,
      Ferdinand

      posted in Cinema 4D SDK
      ferdinandF
      ferdinand