Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Register
    • Login
    1. Home
    2. Havremunken
    H
    • Profile
    • Following 0
    • Followers 0
    • Topics 8
    • Posts 46
    • Best 6
    • Controversial 0
    • Groups 0

    Havremunken

    @Havremunken

    8
    Reputation
    14
    Profile views
    46
    Posts
    0
    Followers
    0
    Following
    Joined Last Online

    Havremunken Unfollow Follow

    Best posts made by Havremunken

    • Project management for C4D SDK projects

      Hi there,
      This is a question to the community of C4D developers as much as to the Maxon guys. I would love to get some feedback and/or discussion on some questions and topics that relate to C4D project management more than the actual SDK itself.

      I'm coming from a background of C# development - so I spend my day job in Visual Studio 2022 as it is, and have not regularly used C++ daily for many years, but I am relearning for a C4D plugin project I am doing. This context affects some of my perspectives.

      1. How are you typically doing source control for your project? In my case, git is used for more or less everything I do, and I will use that to keep track of this project as well. Do you usually put the whole sdk folder in there, or just the folder for your project in sdk/plugins? If you work on multiple different projects at one time, does this change how you approach source control? For instance, do you have multiple sdk folders with one project each, or do you put multiple projects in the same plugin folder and keep them in separate git repositories? Or do you simply have one large ΓΌber-git-repo?

      2. Slightly related to the above - if you support multiple different Cinema 4D versions, how do you do that? Multiple sdk folders (per version), same plugin code base with compiler directives to handle C4D version differences as necessary? I would think supporting different versions would be an argument for keeping only the plugin code in git, but I would love to get perspectives from people with more experience than me in this matter.

      3. I would like to do some unit testing using Google Test in my project. I know about the C4D unit testing support and will probably use that too for stuff that needs to touch C4D. However, for my own code that is just plain C++ code, I would like to get immediate feedback in VS / ReSharper each time I compile. I can probably run all my unit tests a hundered times in the time it takes to start C4D once. However, keeping this in a separate project like I am used to from dotnet was a bad idea - when I needed to re-run the Project Tool, it killed and removed my test project. Another option is to include the test code in my actual plugin project and make sure the test code is stripped out when I do a release build. Anyone else done something similar and want to share their experience?

      4. Another thing the Project Tool does when it runs is to basically overwrite the entire structure of my project. From dotnet I am used to creating folders in my solution (mapped to actual folders on disk) to keep related code together, and not to end up with one big mess of a thousand source files. When I did C++ last, Visual Studio wasn't invented yet, so I don't know how to do the same thing there - the concept of (disk) folders seems not to exist. To keep a minimum of organization I used the feature known as "Filters" to create virtual folders in my project. That works fine, but the Project Tool just kills this structure and I am back to one big folder of source files. I don't NEED to split my code into file-per-class or anything like that, but it helps me wrap my brain around things. How do people go about keeping their projects somewhat organized?

      Any input on any of these points is welcome - I am learning here, and if anyone is willing to share their experiences, I am sure that can be useful to other users too.

      Thanks in advance for any opinions, facts or other comments on these topics!

      posted in General Talk c++ 2024 macos windows
      H
      Havremunken
    • RE: How to properly load async data into C++ generator plugin?

      Hi Ferdinand,

      Once again, thank you so much! I did read the docs for SetDParameter after posting last night and realized the scope of it, so my code is already using it instead of the message notification. Not just to avoid crowded code either. πŸ˜‰ But I have some situations that require validation, adjusting one param based on another etc., so I will soon implement GetDParameter and add that as well.

      Considering that less than 24 hours ago I had never heard of Scene Hooks before, I am now confident I will have your suggestion about using it to handle data loading, parsing, caching etc. implemented in an elegant way shortly. I was afraid I would have to find a contrived way to get the data back to the generator plugin, but using the SceneHookData I should be able to have everything nice and cached, and just use this in GetVirtualObjects to construct the actual geometry from my data structures.

      THANK YOU a million once more, and if you see your boss, tell him hi from me and that you deserve a raise. πŸ™‚

      posted in Cinema 4D SDK
      H
      Havremunken
    • RE: Project management for C4D SDK projects

      One further point I wanted to ask about; At this early stage of building my plugin, I run C4D in the VS debugger a lot; If someone wasn't aware, you can actually change your plugin code while Cinema 4D is running and "hot compile/reload" (Alt+F10) changes without restarting C4D - huge time-saver!

      I do use ApplicationOutput() and DiagnosticOutput() for some things to check that my computations are correct. However, some times it is very useful to see things in the VS debugger as well. Is there a way of seeing the contents of a maxon::String in the VS debugger? I have tried but I can not find anything in the Watch-window or any other way. Since my plugin is dealing with a lot of string value manipulation, it would be very good to see the contents directly in the debugger; Especially since when you hit a breakpoint and look through your code, you can not easily go back to the C4D window (to see output) without resuming the application.

      posted in General Talk
      H
      Havremunken
    • RE: Unexpected "refresh" behavior when manipulating linked object

      Thanks again @ferdinand !

      First; I did confirm that I wasn't dreaming. This works properly when my object is above the text object in the Object Manager. When the text object is above, it doesn't work. We get the splines resizing, but not the cloned text objects (1-9 in my original example). My understanding of how C4D generally works (top down within the same priority group, basically) also says this should be the other way around. As long as the text object is changed first (when I change it's Height property), then creating my clones etc. should be good to go. Instead it is the opposite.

      Let us add some spice to that equation; I added AddToExecution (and after tearing some hair out - added the OBJECT_CALL_ADDEXECUTION to my registration, that wasn't trivial to find) :

      Bool mt::AddToExecution(BaseObject* op, PriorityList* list)
      {
      	list->Add(op, 2147483647, EXECUTIONFLAGS::NONE);
      
      	return true;
      }
      

      Note the very big number in there. Biggest I could find. πŸ˜‰ I tried setting it to everything from EXECUTIONPRIORITY_INITIAL to EXECUTIONPRIORITY_GENERATOR to EXECUTIONPRIORITY_GENERATOR + 500 to the max value. This did NOT change the way this behaves. Only the order of the objects in the Object Manager changes this behavior as far as I can find. And this is still "opposite" of what we would expect.

      One further thing to note - I did override CheckDirty as well, and made it as close as possible to the code in the start of GVO. However, CheckDirty is not passed a HierarchyHelp object (unlike GVO), so I can't really call op->CheckCache(). However, it seems like this is a moot point because according to my debugger, CheckDirty is never actually called by C4D. And unlike the case with OBJECT_CALL_ADDEXECUTION, I could not find a flag to set to register for it. Is there anything special I need to do in order to "activate" the CheckDirty() checking?

      I realize this probably means you need to take a look at my code - I am convinced I am doing something "bad" that causes this priority of the object orders to be the only way that works. I will try to clean up the code a bit - it is an unholy mess right now, obviously programmed by someone who learned C++ 25 years ago, didn't use it much since (spent my time in C#) AND is trying to learn the idiomatic way to do things in the C4D SDK at the same time. Perhaps this cleanup will even fix the problem for all I know.

      I will keep you posted and eventually send you the code if I can't figure out why it behaves this way!

      Thanks again for the help so far!

      posted in Cinema 4D SDK
      H
      Havremunken
    • RE: How to get FONT information and use it to create text objects in C++?

      I can confirm that you were right (nothing unexpected there!) - this is the second time in a couple of weeks where casting has bit me in the behind. I guess I was too spoiled by C# and need to keep my head turned on in the future..

      For anyone from the future reading this: The problem with the code above was READING the value, not WRITING it back to the object. That part was ok. Either passing on for instance op as a parameter or using Get() (if you're on the right object) to get at it is the right move.

      Thanks again!

      posted in Cinema 4D SDK
      H
      Havremunken
    • RE: Plugin does not appear in Expression on client's Cinema 4D

      One thing you could do is run a utility like procmon: https://learn.microsoft.com/en-us/sysinternals/downloads/procmon

      This will let you see what a process accesses on the file system, among other things. Hopefully it will also show you which paths are searched for these libraries, allowing you to identify how to get them in the right location for your customer. πŸ™‚

      posted in Cinema 4D SDK
      H
      Havremunken

    Latest posts made by Havremunken

    • RE: Plugin does not appear in Expression on client's Cinema 4D

      One thing you could do is run a utility like procmon: https://learn.microsoft.com/en-us/sysinternals/downloads/procmon

      This will let you see what a process accesses on the file system, among other things. Hopefully it will also show you which paths are searched for these libraries, allowing you to identify how to get them in the right location for your customer. πŸ™‚

      posted in Cinema 4D SDK
      H
      Havremunken
    • RE: Plugin does not appear in Expression on client's Cinema 4D

      I believe what Ferdinand means is that what is typical for dynamic linking means you need to include libcurl.dll and libcrypto-3-x64.dll with the distribution of your plugin. When Cinema 4D tries to initialize your plugin, it will in turn try to open these to use code from them.

      I would assume that you have them on your system, which is why it works there but not for the customer. πŸ™‚

      posted in Cinema 4D SDK
      H
      Havremunken
    • RE: Plugin does not appear in Expression on client's Cinema 4D

      I can relate to the problem, even if I never experienced this in a Cinema 4D context. I don't know of course the technical level of your customer, but something that hopefully they are able to handle is the console inside of C4D. You can print to that using ApplicationOutput("Some string"); - would it be an idea to compile a debug version for the customer, putting ApplicationOutput statements at various init points in the plugin, and see if these messages show up for them? Unfortunately I don't have the knowledge to look deeper at this myself.

      posted in Cinema 4D SDK
      H
      Havremunken
    • RE: Plugin does not appear in Expression on client's Cinema 4D

      I am not qualified to help you, but do you have any logging in your plugin? If not, could you add it? Logging either to Cinema 4D or to your own log file, it would be interesting to see if your main file is started, if your plugin registration is executed etc. The screenshot seems to be from Windows, and as long as you have SDK compatibility with the C4D version the user has, I would think that C4D at least should make an attempt at loading it. Logging would hopefully let you find out.

      Unfortunately I am not near my C4D machine for many hours so I can't test your plugin at the moment.

      posted in Cinema 4D SDK
      H
      Havremunken
    • RE: How to store "cached" data in the document from the scenehook?

      Hi Ferdinand,

      Yes, I remember reading about that, so the IDs for this container data is 5060 and 5061 (I work in IP telephony as my day job so this is surely no coincidence), but I even tried to move them to 50060 and 50061 and the freeze still happens.

      I will pack up the project shortly and email it in. πŸ™‚

      posted in Cinema 4D SDK
      H
      Havremunken
    • RE: How to store "cached" data in the document from the scenehook?

      Hi @ferdinand,

      First, thanks once more! I loved the more general example you made, but since it showed how to store full "Cinema 4D objects" into the branch and not my simplistic data needs (just two strings), I had to make some assumptions about how to do things. Once more you showed me they were bad assumptions to make. πŸ™‚

      About the CopyTo, I do get the reasons, and I had actually implemented it, but it was also implemented based on the bad assumptions, so I am rewriting it as well. And as for the 0xFFF.. thing I realised of course that this "magic" value of all bits set was not happening by accident, I just could not tell how it happened. But since this happened as another consequence of my poor assumptions about how to implement data storage in a branch, I'll ignore it for now. If it is still there after the code is fixed, then perhaps it is relevant to look at again.

      Your new code example above does shed a lot more light and give me an expanded understanding of how this should work, but like the story where you always go 50% of the remaining distance to the goal, I feel like I am SO close but never getting all the way there. I am sure there are only details missing however. πŸ™‚

      I updated my Read and Write as you instructed, and I abandoned creating all the UrlCacheAssetData nodes manually (I don't want to be a bad citizen after all). So I aim for your point number 3 to store my two strings per node. While it would be fun to do like in the second half of your example and store it in a cube, I used the first part to create the BaseList2D, get the data instance, and then set the strings. I am still registering ID_MORPHINETABLE_URLCACHE_ASSETNODE using RegisterNodePlugin - as an experiment I tried not registering it at all, but then BaseList2D::Alloc(ID_MORPHINETABLE_URLCACHE_ASSETNODE) returned a nullptr which I guess is to be expected. When it is registered I get a real object (e.g. not nullptr), and I also get a not-nullptr when I do asset->GetDataInstance(). However, when I then do data->SetString(ID_MORPHINETABLE_URL, task->url); Cinema 4D completely freezes. The only thing I can really do at that point is to Shift-F5 to stop the Visual Studio debugging session. Edit: This happens when I set the data, i.e. when the user changes the URL parameter in my plugin and the scene hook has loaded the URL contents. So this happens before the whole GetBranchInfo / Read / Write process.

      Could this be because RegisterNodePlugin is the wrong registration method for my asset container? And since in this case I only really need the BaseContainer of the thing to store the two things, how elaborate does the UrlCacheAssetData class really need to be? What you are allocating in your (untested and uncompiled) example is just a BaseList2D, but do I need to make a subclass of that in order to give it the ID_MORPHINETABLE_URLCACHE_ASSETNODE id so I can identify it in my branch for reading and writing? Edit: When I step through in the debugger, the BaseList2D::Alloc() does not invoke my UrlCachetAssetData::Alloc static function as I suspected, which is why I am wondering what role the UrlCacheAssetData class REALLY plays in this scenario beyond registering "something" with the ID_MORPHINETABLE_URLCACHE_ASSETNODE node.

      I am of course also open to the SetString freeze happening for an entirely different reason, but since I don't know how much my UrlCacheAssetData (inheriting from NodeData) implementation matters when we are creating a BaseList2D with its' ID like you are showing, it seems likely that this is another thing I screwed up.

      I will happily pack up the project again if this is impossible to solve without seeing full source. Is my project subdirectory enough, or would you like the whole sdk directory to be able to reproduce 100% what I am seeing?

      Thanks again, and have a great weekend when the time comes!

      posted in Cinema 4D SDK
      H
      Havremunken
    • RE: How to store "cached" data in the document from the scenehook?

      Hi Ferdinand,

      I have worked on fitting your example into my project. As you know, there are two major differences that I needed to account for; first, I am doing this in a Scene Hook, and second, I am not keeping Cinema 4D primitives in my BranchInfo, I am keeping URLs and their contents. So I had to adapt.

      First I implemented GetBranchInfo in my scene hook. It is more or less a copy of yours.

      maxon::Result<Bool> GetBranchInfo(const GeListNode* node, const maxon::ValueReceiver<const BranchInfo&>& info, GETBRANCHINFO flags) const override
      {
      	iferr_scope;
      	yield_scope;
      
      	NodeData::GetBranchInfo (node, info, flags) yield_return;
      
      	if (!(flags & GETBRANCHINFO::ONLYWITHCHILDREN) || _assetHead->GetFirst())
      	{
      		info (
      			BranchInfo{
      				MAXON_REMOVE_CONST (this)->_assetHead,
      				"clever.unique.name.changed.to.protect.the.innocent"_s,
      				ID_MORPHINETABLE_URLCACHE_ASSETNODE,
      				BRANCHINFOFLAGS::NONE
      			}) yield_return;
      	}
      
      	return true;
      }
      

      This will come into play a little later.

      In my scenehook I also implemented the Read, Write and CopyTo (I understand how these go together, but will CopyTo ever really be used in a scene hook? I placed a breakpoint in the function and it didn't get called yet).

      First of all; Since I need something to store my data in, I decided on creating a NodeData subclass like this - the simplest implementation I could imagine getting away with:

      class UrlCacheAssetData : public NodeData
      {
      	INSTANCEOF (UrlCacheAssetData, NodeData)
      
      private:
      	maxon::String _url;
      	maxon::String _data;
      
      public:
      	static NodeData* Alloc()
      	{
      		return NewObjClear (UrlCacheAssetData);
      	}
      
      	static Bool RegisterAssetDataPlugin()
      	{
      		return RegisterNodePlugin (ID_MORPHINETABLE_URLCACHE_ASSETNODE, "UrlCacheAssetDataPlugin"_s,
      		                           PLUGINFLAG_SMALLNODE, UrlCacheAssetData::Alloc, nullptr, 0, nullptr);
      	}
      
      	void SetData(String url, String data)
      	{
      		_url = url;
      		_data = data;
      	}
      
      	String GetUrl() const
      	{
      		return _url;
      	}
      
      	String GetData() const
      	{
      		return _data;
      	}
      };
      

      So when the user enters a new URL into my plugin, I have added code to add a new asset as such:

      auto node = AllocSmallListNode (ID_MORPHINETABLE_URLCACHE_ASSETNODE);
      auto const assetData = node->GetNodeData<UrlCacheAssetData>();
      if (assetData != nullptr)
      {
      	assetData->SetData (*task->url, loadedData);
      	_assetHead->InsertLast (node);
      	_currentCacheSize++;
      }
      

      _assetHead is declared the same way you did in your example. _currentCacheSize is a running count of the number of asset nodes we have.

      Ok, time to save a document (with a plugin that has added at least one item in the cache). Here is my Write implementation for the scene hook:

      Bool Write(const GeListNode* node, HyperFile* hf) const override
      {
      	if (!_assetHead || !hf)
      		return false;
      
      	if (!hf->WriteInt32 (_currentCacheSize))
      		return false;
      
      	auto current = _assetHead->GetFirst();
      	while (current)
      	{
      		auto const assetData = current->GetNodeData<UrlCacheAssetData>();
      		if (assetData != nullptr)
      		{
      			if (!hf->WriteString (assetData->GetUrl()))
      				return false;
      			if (!hf->WriteString (assetData->GetData()))
      				return false;
      		}
      		current = current->GetNext();
      	}
      	return SceneHookData::Write (node, hf);
      }
      

      As you see, my thought is that I first write an integer saying how many url/content pairs I have, then I loop through the asset nodes and write them to the file. I couldn't think of another way to do this, as I do not have the luxury of dealing with objects that already have the WriteObject() functions implemented. I am of course expecting that my way is not the optimal way, or even correct. πŸ™‚

      I step through it using the debugger and all seems to work the way I expect. Ok, I close the file and then try to reopen it using C4D.

      Here is my Read implementation:

      Bool Read(GeListNode* node, HyperFile* hf, Int32 level) override
      {
      	SUPER::Read (node, hf, level);
      
      	iferr_scope_handler
      	{
      		return false;
      	};
      
      	if (!hf || !_assetHead)
      		return false;
      	_assetHead->FlushAll();
      
      	if (!hf->ReadInt32 (&_currentCacheSize))
      		return false;
      
      	for (auto i = 0; i < _currentCacheSize; i++)
      	{
      		auto newNode = AllocSmallListNode (ID_MORPHINETABLE_URLCACHE_ASSETNODE);
      		auto const assetData = newNode->GetNodeData<UrlCacheAssetData>();
      		if (assetData != nullptr)
      		{
      			String url;
      			if (!hf->ReadString (&url))
      				return false;
      			String data;
      			if (!hf->ReadString (&data))
      				return false;
      			assetData->SetData (url, data);
      			_assetHead->InsertLast (newNode);
      		}
      	}
      
      	return true;
      }
      

      I step through it using the debugger and again it works as expected; I read the integer specifying the number of cache items, then loop through that amount of times to read the items. The items are read successfully, containing the expected data! Amazing!

      However, at some point after my Read method is exited, I get a crash. This crash happens while Cinema is executing my GetBranchInfo() code above, specifically the info(...) yield return part. At this point it gets a little difficult for me to look into. I understand that a value is pointing to the wrong place, with a very suspicious value (the "opposite" of a null pointer, so to speak), but I can't tell where this value is coming from.

      Exception details:

      Exception thrown at 0x00007FF8E8427C10 (c4d_base.xdl64) in Cinema 4D.exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF.
      

      This is refering to a location in delegate.h in the SDK where the following code can be seen:

      //----------------------------------------------------------------------------------------
      /// Forwards the call (invokes the stub function for a callable).
      //----------------------------------------------------------------------------------------
      MAXON_ATTRIBUTE_FORCE_INLINE RESULT operator ()(ARGS... args) const
      {
      	StubPtrType stub = StubPtrType(_stubPtr);
      #ifdef PRIVATE_MAXON_MTABLE_PTMF
      	return (reinterpret_cast<Delegate*>(_objectPtr)->*stub)(std::forward<ARGS>(args)...);
      #else
      	return stub(_objectPtr, std::forward<ARGS>(args)...);
      #endif
      }
      

      Line 761-772 in my 2024 SDK. I don't know where exactly the 0xFFF... is coming from but it is not the stub/_stubPtr and the exception happens in the line with the reinterpret_cast.

      The call stack does not tell me a lot apart from this happening while Cinema is running my GetBranchInfo:
      2971ec64-f0ee-4fac-bc0b-9fed1123f3f0-image.png

      I realize of course that debugging this based on a forum post is hopeless - unless the 0xFFFF... value could be caused by only one very well known thing, I expect you would need my complete code for this? It changed quite a bit since last time.

      I am quite sure that there is something that is not properly initialized or something along those lines, since this happens only when I try to open a document saved with my branch info in it. Oh, and for completeness, my asset head is declared as a private instance variable in my scene hook like this:

      AutoAlloc<GeListHead> _assetHead;
      

      And I also borrowed from your init code and put it in the same class.

      Bool Init(GeListNode* node, Bool isCloneInit) override
      {
      	if (!_assetHead)
      		return false;
      
      	_assetHead->SetParent (node);
      
      	return SUPER::Init (node, isCloneInit);
      }
      
      

      If you want me to send you the code, just let me know. If you want me to change or test anything else, the same. And if I am completely off track with my asset implementation, doing something that couldn't possibly work - please don't be afraid to tell me. I'm a big boy, I can take it. 😁

      Thanks again!

      posted in Cinema 4D SDK
      H
      Havremunken
    • RE: How to store "cached" data in the document from the scenehook?

      "Thank you" seems poor and inadequate for that fantastic example, but I don't have the English vocabulary to go beyond that!

      I have read through the example once, and I think I understand it. Since this has been a real Monday (tm), I'm going to let this simmer in the brain for a day or two, and then use the techniques you demonstrate to add GetBranchInfo etc. to my scene hook. Both the example and the video were great at explaining the steps needed to get "extra" information into the document, and are much appreciated!

      So while it does not express the full extent of my gratitude, once again - thank you!

      posted in Cinema 4D SDK
      H
      Havremunken
    • RE: How to store "cached" data in the document from the scenehook?

      Thank you so much, Ferdinand, I look forward to that! And enjoy the well-deserved weekend in the mean time! πŸ™‚

      posted in Cinema 4D SDK
      H
      Havremunken
    • RE: How to store "cached" data in the document from the scenehook?

      This is perhaps not a big deal, but while implementing this, I met some resistance from Visual Studio while overriding GetBranchInfo in my scene hook. It did not match the signature from your example. Ok, so detective time - my scene hook inherits from SceneHookData, which has no GetBranchInfo of its own, this comes from it inheriting from NodeData, and this class does have a GetBranchInfo. However, the signature does not match entirely. I am on 2024 still, just in case this changed for 2025. This is the signature:

      virtual maxon::Result<Bool> GetBranchInfo(const GeListNode* node, const maxon::ValueReceiver<const BranchInfo&>& info, GETBRANCHINFO flags) const;

      Ok, sligtly different, but... It is supposed to return a bool? Ok, that is a bit confusing, in your example you returned the number of elements we filled in. Ok, let me look at the docs in the source file (c4d_nodedata.h):

      /// @return The number of BranchInfo elements filled in the @formatParam{info} array.

      Ok, that is clear as mud. 😏 So I am not supposed to return a number, then, but just true if I actually put something in there? How does it learn the number of items, or doesn't it need to?

      A minor point is that in your code example (in your first post) you write it as FlowTag::GetBranchInfo - I guess I can safely assume this was copied from another source example where a FlowTag class was implemented, so the name "FlowTag" has no meaning in this case?

      From your example I get the sense that the MyAssetData is created in a way where one instance of the class represents one piece of data. In my case, my variant of this asset node would contain one URL and one content string. Then I use the list starting with the AssetHead to store each url+content combo I have in my cache, is this correct? So my version of AddAsset would take these two as params?

      I am also trying to understand the choice to "feed" the asset object by sending it a message, instead of for instance calling Load directly. Is this because when you BaseList2D::Alloc(Tassetnode); you don't actually get direct access to the instance of the MyAssetData class itself, so we're in the Data Layer instead of in the Logic Layer, and have to use this mechanism?

      Hopefully final question in this round (at least I'm not one of the many spammers that keep trying their luck on the forum, huh?): When I create an object that causes some data to be cached using this system, and save the C4D file, then later reopen it - I understand that C4D reads this data from the file, and I imagine that the searching lambda in your GetAssetHead is what locates this again the first time it is called (when _assetHead is not already set). Fairly soon after opening the file, C4D will call GetVirtualObjects on my main plugin, and it will ask the scene hook for the data - am I correct in assuming that this would be when the scene hook calls GetAssetHead(), reads all the MyAssetData (or whatever I end up calling them) nodes, and finally has his cache so he can return data to the generator plugin?

      I hope these questions are not too annoying, I am just trying to understand the code rather than just copy & paste it (or feed it to an AI). πŸ™‚

      Thanks!

      posted in Cinema 4D SDK
      H
      Havremunken