• 0 Votes
    6 Posts
    312 Views
    ferdinandF
    Hey @aghiad322, Thank you for your code. It is still very unclear to me what you are doing on a higher more abstract level, and on a concrete level, where exactly you want to detect something. Find below your commented code and at the end a few shots into the dark from me regarding what you are trying to do. I also just saw now that you posted in the wrong forum. I moved your topic and marked it as C++ and 2025 since you said you are not using the 2026 SDK. I hope this help and cheers, Ferdinand // I wrote this blind without compiling it. So ,there might be some syntax issues in the code I wrote, // but it should still illustrate the concepts well enough. #include "maxon/weakrawptr.h" using namespace cinema; using namespace maxon; struct NexusMember { // While we could consider a pointer somewhat conceptually a weak reference, it is factually // not one, as the pointed object being deleted does not invalidate the pointer. This can lead // to dangling pointers and access violation crashes. BaseObject* object = nullptr; // weak ref, don’t own it Bool isChild = false; // "include children" flag // This is better. WeakRawPtr<BaseTag> _tagWeakPtr; // Gets the tag pointed to by this member, or nullptr if it has been deleted. BaseTag* GetTag() const { return _tagWeakPtr.Get(); } // Sets the tag for this member. void Set(const BaseTag* tag) { _tagWeakPtr = _tagWeakPtr.Set(tag); } }; struct NexusGroup { Vector color; // No, do not use the std library. Cinema 4D modules are by default compiled without exception // handling for performance reasons, and the standard library uses exceptions for error handling, // making its behavior undefined in such builds. std::vector::push_back() can throw // std::bad_alloc, for example. std::vector<String> links; std::vector<NexusMember> members; Int32 dirtyLevel = 0; // MUST be: BaseArray<String> links; BaseArray<NexusMember> members; }; class NexusRegistry : public SceneHookData { public: static NexusRegistry* Get(BaseDocument* doc); static NodeData* Alloc(); virtual Bool Message(GeListNode* node, Int32 type, void* data); virtual EXECUTIONRESULT Execute(BaseSceneHook* node, BaseDocument* doc, BaseThread* bt, Int32 priority, EXECUTIONFLAGS flags); // The same applies here, the Maxon API alternatives to unordered_map are: // // * HashSet (just a hash set of fixed type values without keys) // * HashMap(a hash map of fixed key and value type), // * DataDictionary (a hash map of arbitrary key and value types). std::unordered_map<Int32, NexusGroup> groups; maxon::BaseArray<BaseTag*> pendingRegistration; void ProcessPendingTags(BaseDocument* doc); void RebuildRegistry(BaseDocument* doc); void UpdateGroupFromTag(BaseDocument* doc, BaseTag* tag); void RemoveObjectFromGroups(BaseObject* obj); void RemoveTagFromGroup(BaseTag* tag); const NexusGroup* GetGroup(Int32 hash) const; }; // ------------------------------------------------------------------------------------------------- void NexusRegistry::UpdateGroupFromTag(BaseDocument* doc, BaseTag* tag) { if (!tag) return; BaseObject* obj = tag->GetObject(); if (!obj) return; BaseContainer* tagContainer = tag->GetDataInstance(); String id = tagContainer->GetString(ID); // I do not know of which nature this HashID is, but our API has multiple hash functions. Int32 hashedID = HashID(id); // There is for once StringTemplate::GetHashCode(). I.e., you could do this: const HashInt = id.GetHashCode(); // But all scene elements already have a marker on them which uniquely identifies them (if that // is what you are after). // Uniquely identifies over its time of creation and the machine it was created on. I.e., this // value is persistent across sessions and unique across machines. const GeMarker uuid = tag->GetMarker(); Bool includeChildren = tagContainer->GetBool(CHILDREN); Int32 oldIdHash = tagContainer->GetInt32(NEXUS_TAG_PREV_ID, NOTOK); if (oldIdHash != NOTOK && oldIdHash != hashedID) { auto it = groups.find(oldIdHash); if (it != groups.end()) { auto& members = it->second.members; // std::vector::erase is not noexcept, this can crash Cinema 4D, unless you compile your // module with exception handling enabled (which we do not recommend for performance // reasons). I am not going to repeat this comment in similar places below. members.erase(std::remove_if(members.begin(), members.end(), [obj](const NexusMember& m) { return m.object == obj; }), members.end()); it->second.dirtyLevel++; if ((Int32)members.size() == 0) groups.erase(it); } } // Update new group NexusGroup& group = groups[hashedID]; // Remove duplicates of this object first group.members.erase(std::remove_if(group.members.begin(), group.members.end(), [obj](const NexusMember& m) { return m.object == obj; }), group.members.end()); group.members.push_back({ obj, includeChildren }); ((Nexus*)tag)->UpdateInfo(doc, tag); // Store current ID for next update tagContainer->SetInt32(NEXUS_TAG_PREV_ID, hashedID); } // ------------------------------------------------------------------------------------------------- void NexusRegistry::ProcessPendingTags(BaseDocument* doc) { if (pendingRegistration.IsEmpty()) return; Int32 i = 0; while (i < pendingRegistration.GetCount()) { BaseTag* tag = pendingRegistration[i]; BaseObject* op = tag->GetObject(); if (op) { UpdateGroupFromTag(doc, tag); // This is not how our error system works. Functions of type Result<T> are our exception // handling equivalent. You need iferr statements to catch and/or propagate errors. See // code below. maxon::ResultRef eraseresult = pendingRegistration.Erase(i, 1); } else { i++; } } } // ------------------------------------------------------------------------------------------------- // See https://developers.maxon.net/docs/cpp/2026_0_0/page_maxonapi_error_overview.html for a more in detail // explanation of our error handling system. // So we have some class with a field whose type has a function of return type Result<T>, e.g., your // NexusRegistry. We have now three ways to handle errors when calling such functions: // Ignoring errors (not recommended): void NexusRegistry::AddItem(const String name) { links.Append(name) iferr_ignore("I do not care about errors here."); // Append is of type Result<void> } // Handling errors locally, i.e., within a function that itself is not of type Result<T>. Bool NexusRegistry::RemoveItem(const String name) { // The scope handler for this function so that we can terminate errors when the are thrown. iferr_scope_handler { // Optional, print some debug output to the console, #err is the error object. DiagnosticOutput("Error in @: @", MAXON_FUNCTIONNAME, err); // We just return false to indicate failure. If we would have to do cleanup/unwinding, we // would do it here. return false; }; const Int32 i = links.FindIndex(name); // We call our Result<T> function and propagate any error to the scope handler if an error // occurs. The iferr_return keyword basically unpacks a Result<T> into its T value, or jumps // to the error handler in the current or higher scope and propagates the error. const String item = links.Erase(i) iferr_return; return true; } // And the same thing in green but we propagate errors further up the call chain, i.e., our function // is itself of type Result<T>. It now also does not make too much sense to return a Bool, so our // return type is now Result<void>. Result<void> NexusRegistry::RemoveItem(const String name) { // Here we just use the default handler which will just return the #err object to the caller. iferr_scope; const Int32 i = links.FindIndex(name); const String item = links.Erase(i) iferr_return; return OK; // Result<void> functions return OK on success. } // ------------------------------------------------------------------------------------------------- EXECUTIONRESULT NexusRegistry::Execute(BaseSceneHook* node, BaseDocument* doc, BaseThread* bt, Int32 priority, EXECUTIONFLAGS flags) { ProcessPendingTags(doc); return EXECUTIONRESULT::OK; } // ------------------------------------------------------------------------------------------------- // So, all in all, this does not shed too much light on what you are doing for me :) The main questions // is if you implement your tags yourself, i.e., the items stored in your NexusGroup::members. // When you implement a node yourself, you can override its ::Read, ::Write, and ::CopyTo functions // to handle the node serialization and copying yourself. See https://tinyurl.com/2v4ajn58 for a // modern example for that. So for your, let's call it NexusTag, you would do something like this: class NexusTag : public TagData { Bool CopyTo(NodeData* dest, const GeListNode* snode, GeListNode* dnode, COPYFLAGS flags, AliasTrans* trn) const { // This is a copy and paste event. There is no dedicated event for CTRL + DRAG you seem // to after. if (flags & PRIVATE_CLIPBOARD_COPY) { // Do something special with the destination node #dnode or call home to you registry. } else { // Do something different. } // We should always call the base class implementation, unless we want interrupt the copy. return SUPER::CopyTo(dest, snode, dnode, flags, trn); } }; // --- // Another way could using a MessageData hook and monitoring the EVMSG_CHANGE events, i.e., when // something in a scene changed. This is usually how render engines synchronize scene graphs. I am // not going to exemplify this here, as this is a lot of work.But you can have a look at this thread // which is the most simple example we have for this (in Python, but is more or less the same in C++): // https://developers.maxon.net/forum/topic/14124/how-to-detect-a-new-light-and-pram-change // Here you do not have to own the tag implementation. But you could not detect how something has // been inserted, only that it has been inserted. // --- // Yet another thing which could help are event notifications. I.e., you hook yourself into the copy // event of any node (you do not have to own the node implementation for this) and get notified when // a copy occurs. But event notifications are private for a reason, as you can easily crash Cinema // with them. You will find some material on the forum, but they are intentionally not documented. // https://tinyurl.com/2jj8xa6s // --- // Finally, with NodeData::Init you can also react in your node to it being cloned. Bool NexusTag::Init(GeListNode* node, Bool isCloneInit) { if (isCloneInit) { // Do something special when this is a clone operation. } return true; }
  • 1 Votes
    4 Posts
    252 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: [image: 1760086817339-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). [image: 1760086755748-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
  • 0 Votes
    13 Posts
    892 Views
    ferdinandF
    Hey, your second code snippet never sets self._result. Regarding loading vs. cloning documents: That I did it how I did it was no accident, but that does not necessarily mean that cloning things is bad. C4DAtom::GetClone is implemented in the different scene elements independently; i.e., BaseObject::GetClone, BaseDocument::GetClone, BaseTag::GetClone, etc. and C4DAtom::GetClone is just the empty implementation. The different implementations then rely on C4DAtom::CopyTo to copy data from the reference into a new instance of that scene element type. On top of that comes that Cinema 4D is largely Copy-on-Write these days, with data actually only being copied when you try to modify it. This all explains why BaseDocument::GetClone is so inexplicably performant, it just copies the metadata and only copies the real payload of the scene when it has to. On top of that comes that cloning from the same document from multiple threads in parallel could entail read-access violations (although somewhat unlikely). On the other hand, our rendering pipeline does exactly the same, it clones documents for rendering (the cloning is however done on the main thread). I personally would say what you are doing is probably okay, but I would not write such code as example code. I would have to spend more time on this to figure out if this is absolutely safe. Doing the actual cloning off-main-thread seems risky though (but is probably also fine in 99,9% of the cases). Cheers, Ferdinand
  • Debug Scene / Generators (Scene heat map)

    Cinema 4D SDK windows macos
    2
    0 Votes
    2 Posts
    250 Views
    ferdinandF
    Hey @indexofrefraction, Thank you for reaching out to us. The Object Profiler should do what you want to do. [image: 1750425151882-7f8ba2c2-8af1-448e-a0d4-f120e3b91e0b-image.png] It is part of Cinema 4D since 2025.0.0. Cheers, Ferdinand
  • 0 Votes
    4 Posts
    445 Views
    L
    Thank you very much @ferdinand for your suggestions—I really appreciate your input and support. I will definitely experiment with your leads and see what works best for me. It’s always helpful to get an outside perspective, and your advice has given me some new things to think about. Thanks again!
  • Problem building the SDK examples on macOS

    Cinema 4D SDK 2025 macos c++
    8
    0 Votes
    8 Posts
    1k Views
    S
    I actually quite like the Apple keyboard, even if Apple’s idea of a UK keyboard is different to everyone else. For example, shift-2 should produce a “ character but on this Apple kit, it’s the @ symbol. The odd key bindings just make it worse, but it’s a nice keyboard. But I detest the Apple Magic Mouse, I can’t get used to those ‘gestures’. Give me my Logitech trackball any time. A bit of extra software does make a Mac so much more useful though. Pathfinder is way better than the horrible Finder, and BetterZip is very user-friendly.
  • 0 Votes
    5 Posts
    897 Views
    i_mazlovI
    Hi @d_keith, I would kindly ask you to check our Support Procedures, namely the "How To Ask Questions" paragraph: 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. Break up your questions into multiple topics. Here you effectively have 4 different questions about Asset Browser, and these are candidates for 4 different threads on the forum. In your further postings please try to follow the aforementioned rules. Regarding your questions: Should I be able to mount a directory and have it auto-create a DB? Mounting database is effectively executing the AssetDataBasesInterface.SetDatabases. It has nothing to do with creating database neither semantically, nor is this mentioned in the docu. If you need to create repository, please use maxon.AssetInterface.CreateRepositoryFromUrl(), it will scan the directory for being already a database and create proper dir structure if it's not. Any idea why I need to re-try creating the Repo for it to work? If you face any errors in the script, please always attach at least the error message! In this case I assume you receive the following error, when executing the maxon.AssetRepositoryTypes.AssetDatabase() for the first time after Cinema 4D started. Looks like a bug to me, I've created a bug report for that (ITEM#585831). The error message: Traceback (most recent call last): File "console", line 1, in <module> File "C:\Program Files\Maxon Cinema 4D 2025\resource\modules\python\libs\python311\maxon\interface.py", line 5049, in __call__ self._cachedObj.R = _maxon_mapping.GetAssociatedDataType(dt) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Exception: unable to find datatype As a workaround you can just execute the following line first in your main(): maxon.AssetRepositoryTypes.AssetDatabase() ... about multiple DBs ... You're giving your databases unique IDs with the line repo_id = maxon.AssetInterface.MakeUuid(str(url), True). If you need them to be the same, just pick one instead, e.g. repo_id = maxon.Id('net.maxon.sdk.cool.things.repo') ... revealing assets doesn't work... I've created a bug report for that, as it looks like a bug with refreshing in the Asset Browser. As a workaround you can reload databases and reopen the AB before reveling your assets, e.g.: def RepenAssetBrowser(): CID_ASSET_BROWSER = 1054225 # Close the Asset Browser if it's alredy opened if c4d.IsCommandChecked(CID_ASSET_BROWSER): c4d.CallCommand(CID_ASSET_BROWSER) # Open again c4d.CallCommand(CID_ASSET_BROWSER) def main(): # ... # assets = [] # ... # assets.append(asset) # ... maxon.AssetDataBasesInterface.ReloadAssetRepositories(True) RepenAssetBrowser() maxon.AssetManagerInterface.RevealAsset(assets) Cheers, Ilia
  • 0 Votes
    3 Posts
    693 Views
    B
    Thank you @ferdinand for the help! Write raw memory does help a lot, appreciate!
  • 0 Votes
    10 Posts
    1k Views
    B
    Thank you very much for all your detailed explanation, @ferdinand!
  • 0 Votes
    6 Posts
    721 Views
    ferdinandF
    Hello @uogygiuol, Thank you for the added details. Yes, reducing the complexity of questions is the right thing to do, thank you for doing tit. Essays are counterproductive, as we then tend to overlook things (q.e.d., I overlooked the fact that you wanted to mangle the scene file in this thread). In general, trying to mangle a file beforehand is not a good route, as you always risk invalidating the file. For your very specific scenario - very simple scene graph, just geometry, no materials, animations or other dependencies - it could make sense. I briefly talked with the owner of our GLTF-importer, and we do not do any sanity checking, e.g., comparing nodes with meshes. So, you could just 'clean up' the scene graph ("nodes") of the file, and Cinema's GLTF importer will then just ignore extra data in fields such as "meshes". How fruitful this will be, you will have to find out yourself. I already had the hunch that your are here surfing on the edge of what is sensbible, and GLTF JSON files which translate to gigabytes of memory are certainly an edge case, due to the fact that text-based file formats are usually a bad choice for such heavy data. Using Python to Read JSON My guesstimate would be that when you throw a GLTF JSON file at Python's JSON parser - which takes five minutes to load in Cinema 4D - to mangle it, you end up with a net-loss or tie, because you loose most or more than the won time in that Python JSON stage. Python's json module is mostly written in C to make it performant, but that is still a lot of JSON to deserialize, modify, and then serialize. One idea could be to use re, i.e., regular expressions, to find the "nodes" section in that file, just deserialize that from JSON, modify it, serialize back to a JSON string, and write it back in place, and by that sidestep having to deserialize that whole file. The problem with all that is that json.load allows you to pass a file object, allowing you to bypass the Python VM entirely and let the data reside in C until the parsing is done, while re does not allow you to regex a file object directly (AFAIK), you always must read the file object into lines or chunks to then pass these strings to the re module. I.e., you would have to load that whole file into a Python string first. What would come here out on top, I have no clue, but my hunch is that re might loose, as Python's string handling is not the fastest. Alternatives might be 3rd party libs such as isjon (a lazy JSON loader) but I do not know how performant it is. For this section it would make a huge difference if you could predict the position of "nodes" in the file, either exactly as a chunk offset, or in the form of 'I know that it is always very close to the end, so let's regex parse the file in reverse'. Using a Binary File Format But the fact remains that text-format file types, e.g., JSON GLTF, become extemely ineffcient once you pass the ~100 MB barrier. Using something like binary GLTF or another binary format such as FBX will likely speed up your Cinema 4D loading times quite a bit, no extra steps required. And to be clear, text-based file formats are always wildely ineffcient. It is just that below the ~100 MB barrier (adjust for the beefiness of your machine), you can drown that inefficency with pure computing power and have the nice advantage of a human-readble file format. Cheers, Ferdinand
  • WebSocket usage in C++

    Cinema 4D SDK c++ windows macos s24
    6
    1
    0 Votes
    6 Posts
    768 Views
    C
    Hi @m_adam, following your typescript example it worked now to connect! Thank you very much for your help Merry Christmas and a Happy New Year!
  • Syntax highlight in VS Code under MacOS

    Cinema 4D SDK python macos
    4
    0 Votes
    4 Posts
    849 Views
    ferdinandF
    I would heavily recommend using the extension, as it will automatically curate the paths for you. I.e., when you use the extension and connect to a Cinema 4D instance, it will make sure that the dummy modules of that Cinema 4D version are on the search paths. But when you really do not want to use it, you can also just edit your config so that the dummy module paths are discoverable for auto complete and the linter. [image: 1731583351292-2a76cd6c-35aa-451f-82db-02b03694e72d-image.png] What you will need in any case, is the Python and Pylance extension for VS Code, as they are the extensions which make use of these settings. When you install the connector, they will be installed automatically as a dependency. [image: 1731583415824-0b5d77af-5f23-4203-9a0a-276b8eafc62e-image.png] Cheers, Ferdinand
  • 0 Votes
    3 Posts
    700 Views
    B
    Thank you, @f8bet00net. Yeah, I remember I had gone though this with you before. But recently, we found there is a way to customize TreatSpecificWarningsAsErrors settings in projectdefinition.txt for MSVCBase.props for windows VS projects. So I asked this question again just to double confirm if we could do similar things for MacOS XCode settings. Thanks for confirming this is not possible on MacOS.
  • MacOS C4D Python app questions

    Cinema 4D SDK python macos
    4
    0 Votes
    4 Posts
    712 Views
    ferdinandF
    Good to hear. When you want to know more about how to expose libraries, I would recommend reading the Python Libraries Manual, as there are quite a few differences to a vanilla CPython. The guide is a little bit dated, I haven't updated it yet to the pip support Maxime is adding, and I also did not yet cover there mxutils.LocalImportPath. Cheers, ferdinand
  • Notarizing a Mac plugin

    Cinema 4D SDK c++ macos
    2
    1 Votes
    2 Posts
    676 Views
    ferdinandF
    Hey @spedler, Thank you for reaching out to us and for pointing out that issue. We are aware that our code signing documentation requires an overhaul. This not only means updating the rather dated MacOS guide, but also providing a guide for Windows since code signing also has become more and more important under Windows. And although not yet as restrictive as MacOS, the Microsoft Secure Future Initative is pointing to a future of execution policies on Windows similar in strictness to the one's found on MacOS. Cinema 4D itself is evolving in a similar fashion, as recently lined out in About the necessity of code signing plugins. We have currently no immediate plans to make code signing for all plugins technically mandatory, Cinema 4D is currently still loading unsigned binaries, but we strongly encourage users to (properly) sign their plugins, especially under MacOS. What has changed since Cinema 4D 2024, is that Cinema 4D will not load binaries with an expired certificate anymore (note that an expired certificate is not the same as an expired license, see the linked posting for details). I currently plan to update the guides in 2025 Q1 or Q2. It was actually already planned for 2024 but I never got to it. But just before I left for vacation I at least already requested the necessary licenses to further research and write the new guides But this is neither my current or next task. However, given the relative closeness of the task of overhauling the code signing documentation, I will probably not 'monkey patch' the current documentation. When there are any questions regarding code signing plugins for Cinema 4D on either Windows or MacOS, please do not hesitate to ask or discuss them here. Cheers, Ferdinand PS: I am still on vacation, so I will likely not respond to any follow-ups until I am back.
  • Copy to the OS clipboard

    Cinema 4D SDK windows macos
    2
    0 Votes
    2 Posts
    410 Views
    i_mazlovI
    Hi @César-Vonc , Cinema 4D uses OS clipboard to some extent, namely as you can see from the CLIPBOARDTYPE enum there's text and image clipboard options. For other Copy&Paste functions the built-in clipboard system is used, hence the OS clipboard stays untouched. Cheers, Ilia
  • Development requirements for C4D 2025

    Cinema 4D SDK c++ macos
    10
    0 Votes
    10 Posts
    3k Views
    ferdinandF
    Dear development community, just as a clarification, as I was not very clear about that above. We are working on a solution for the build system for the SDK (as I hinted at before in other postings). But for 2025 we will stay with this a bit cumbersome legacy build system solution for macOS. Please excuse the inconvenience but there are a few more moving parts in the background than it is obvious from the outside (to fix this, we must move away from the project tool). Cheers, Ferdinand
  • 0 Votes
    8 Posts
    2k Views
    ferdinandF
    Hey everyone, I fixed the issue, the legacy SDKs now have again the correct line endings, the downloads have been updated. Cheers, Ferdinand
  • 0 Votes
    7 Posts
    1k Views
    justintaylor-devJ
    @ferdinand Great thanks!
  • Volume Builder GetInputObject returns something different?

    Moved Bugs 2024 c++ macos
    5
    0 Votes
    5 Posts
    1k Views
    D
    Thanks for the info! Dan