SOLVED Changing Asset References to Absolute

Hi,

following problem described from user point of view:

  1. Project A gets saved via "Save Project with Assets..." (all asset references get converted to relative references, all assets get transferred into the target tex folder. All working nicely via MSG_GETALLASSETS + MSG_CLEARSUGGESTEDFOLDERS messages).

  2. User wants to merge above saved Project A into Project B. Problem: No asset reference is working, because this operation does not seem to take conversion of asset references from relative to absolute into account, nor does it copy any assets over into the target project's folder.

I reproduced this behavior in versions R17 to S24. I'd probably rather call this a bug than a missing feature, because in other places C4D solves this correctly (e.g. when copy/pasting from another document) by asking the user, what to do with the participating assets.

I would very much like to solve this issue for a plugin, where MergeDocument() gets used quite heavily. Preferably without copying assets around manually. And also without trying to fix all asset references manually inside a document. It seems as if MSG_RENAMETEXTURES could be coming in handy and while the symbol is not documented in Python docs, it is yet available.

But trying to do a broadcast like so:

    msg = {'oldname' : path, 'newname' : pathNew, 'doc' : docToMerge, 'changecnt' : 0, 'noundo' : True}
    result = docToMerge.MultiMessage(c4d.MULTIMSG_ROUTE_BROADCAST, c4d.MSG_RENAMETEXTURES, msg)

I agree, it was already a bit far fetched to hope to "emulate" the needed RenameTextureMessage stucture via a dictionary. So I was not too surprised to see it not working. Yet, it locks up C4D completely, which perhaps is a bit too hard of a sentence for trying to figure out, how an undocumented message may work. 😉
And using MultiMessage(c4d.MULTIMSG_ROUTE_NONE) or MultiMessage(c4d.MULTIMSG_ROUTE_ROOT | c4d.MULTIMSG_ROUTE_DOWN) instead does not lock up C4D, but simply seems to do nothing.

So, I guess, my actual question is: Is it possible to use MSG_RENAMETEXTURES from Python at all? And if so, how?

I assume it is probably not, as there seems to be no way to properly provide RenameTextureMessage data via Python.

Maybe I should also explain why I I'd prefer to solve this issue without manually copying assets (a) and without trying to manually fix the asset references inside a document (b):

a) This is related to a second thread I will be posting in a minute. It simply seems not to be completely trivial to identify all assets really in use in a document (I do know about GetAllTextures()).

b) This seems to be an even harder task. Already for all built-in stuff it would mean to iterate all branches and I think, I remember from the past that it can be non-trivial to identify all references to assets. Yet for built-in stuff, this could work by somehow examining descriptions of all entitities. But taking for example 3rd party renderers into account, I could imagine such references being hidden in some custom nodal shader networks, making this even more complicated.

Thanks in advance for taking a look.

Cheers

Hi,

Well, I thought "Andreas", but my fingers typed something else. Sorry.

Any particular reason why you do not use GetAllAssetsNew? This function has the flag ASSETDATA_FLAG_CURRENTFRAMEONLY that could be the answer to the other thread. (Ferdinand will answer it)

You also have this thread where Riccardo use it to change the path of textures.

You also have the object from where it come from and the Id of the parameter.

About the fireproof well, that's what the 'save project with assets' use. We don't better i would say.

Cheers,
Manuel

Hi Andreas,

Could you please use the tags and the "ask a question" feature of the forum? ^^

Creating MSG_RENAMETEXTURES is not possible in python.

Your best chance is to open the project A, retrieve all the assets using GetAllAssetsNew and make them absolute path and after that merge the documents.

Cheers,
Manuel

Hi,

my name is Andreas. And yes, sorry, I forgot to set the tags. When I realized, you had already done so.

And I was afraid of this answer. Yet, can you give me a hint, how to make all asset references absolute in a scene, considering all kinds of scene ingredients and plugins? I mentioned, that I am aware of this option and that I would consider this difficult to achieve. Maybe I'm wrong and it is easier as I think. Can you give me a hint? Especially as I mentioned in a second thread, GetAllTextures() does also not seem like a fireproof way of determining all resources.

Cheers

Edit: Now thinking about it, I actually had set the tags in this thread. What I forgot was, to set it as a "Question".

Hi,

Well, I thought "Andreas", but my fingers typed something else. Sorry.

Any particular reason why you do not use GetAllAssetsNew? This function has the flag ASSETDATA_FLAG_CURRENTFRAMEONLY that could be the answer to the other thread. (Ferdinand will answer it)

You also have this thread where Riccardo use it to change the path of textures.

You also have the object from where it come from and the Id of the parameter.

About the fireproof well, that's what the 'save project with assets' use. We don't better i would say.

Cheers,
Manuel

Hi Manuel,

thanks for the quick answer.

GetAllAssetsNew() is an S22 function. I need to support R17 to S24 and following. So that's unfortunately not a real option in my case. While it certainly is a nice function to know about. I had overlooked it completely up to now. Thanks.

Thus I will have to find all asset references manually. I guess, this includes iterating all objects, tags and materials (including all subshaders), including all their branches. And for all of these I will then need to browse the entire description in order to find any entries of types DTYPE_FILENMAME, DTYPE_TEXTURE and DTYPE_STRING. Additionally probably all parameters of types DTYPE_SUBCONTAINER and DTYPE_LINK would need further examination. And with the last one one would most likely need to be extra careful not to end up iterating in an endless loop...

But even then, I'm not sure I would get everything. I may be wrong, but I remember some of the old SLA shaders not really adhering to the rules. Also I think for example the MultiShader did not properly handle subshaders as children. So in these cases I will probably also need to check the descriptions for other types like subshaders, in order to continue iterating over these as well. And up to here we are not even talking about third party materials, shaders, nodal networks, etc...

Plus all of this will be needed to be examined over the entire frame range?

But maybe I'm overcomplicating things and it's way easier. Not sure.

Cheers,
Andreas

Edit: Typos
Edit (obviously I submitted too fast, sorry): Added other data types to consider.

About the fireproof well, that's what the 'save project with assets' use. We don't better i would say.

I think, "Save Project with Assets" is a bit simpler, as it only needs MSG_GETALLASSETS and MSG_CLEARSUGGESTEDFOLDERS, if I'm not mistaken. These we have available in Python as well. But I need to revert the process. And since MSG_RENAMETEXTURES is missing, I'm afraid it will get tedious in best case. With that message, it's in the responsibility of every entity to react correctly, well knowing the assets it uses. But without, I will have to manually find out, and that is in my mind as described above not completely trivial.

But don't get me wrong. I do not blame you. Not at all.

Though I certainly would appreciate, if Maxon at least considered fixing the MergeDocument() (in SDK as well as for users). That won't help me at all. But would be nice. Plus I wouldn't be sad to have the entire "trio" of messages (MSG_GETALLASSETS, MSG_CLEARSUGGESTEDFOLDERS and MSG_RENAMETEXTURES) available in Python. Doesn't help me either, now, but might be nice for future projects.

Cheers

you are right, that's the other way around, GetAllAssets (and GetAllAssetsNew) are doing the same than "Save Project with assets.. " and they all broadcast MSG_GETALLASSETS. I will talk with others tomorrow again 🙂

Cheers,
Manuel

I have the feeling, I sound like I'm not appreciating the help you are trying to provide. That is not my intention. I appreciate your answers a lot. And I am well aware you can not provide support back to R17, nor is it your job to provide me with a solution.

The main question you have already answered. MSG_RENAMETXTURES is not available, so I can stop trying to get that approach working.

Otherwise my only hope is, I may be thinking way too complicated and some hint from you might be able to interrupt the loop in my head.

I have the feeling, I sound like I'm not appreciating the help you are trying to provide.

Not at all but I'm afraid there will be no solution from r17 to s22..

I will need to check the difference between GetAllAssets and GetAllAssetsNew because GetAllAssets is there since r15.

Cheers,
Manuel

GetAllAssets() only provides me with a list of filenames. But no information, which entities are using a reference to these, nor which parameter the reference would be.
Anyway, don't worry. As you correctly stated, there will be no easy solution covering the version range I need. Which leaves me with the route of doing it manually.

I am so dang stupid!

All the time I assumed we were talking about the same function, but we are not. I apologize. I was completely stuck with GetAllTextures(), not realizing you were talking about GetAllAssets(). Even after reading the docs of GetAllAssetsNew() I was completely blind to this fact.

I apologize, probably evidence, yet, no excuse, how badly this problem was weighing on my mind... Yes, GetAllAssets() indeed makes a difference. Sorry, sorry!!!

Edit: The one being capable of reading clearly has an advantage in life...

Hi,
well i didn't posted my answer this morning.

About the difference between GetAllAssets and GetAllAssetsNew, the New was introduced to change the returned value and to keep binary compatibility between versions.

That's explain why i got the feeling we were not on the same track ^^

The problem is that the Owner have been added in R20 only, so even GetAllAssets will not help you with previous version. So, you are back to the problem with almost no solution from the sdk.

Side note: one question, why are you merging those documents? If it's to render them (with some sort of studio setup), you can add the first tex folder to the asset list in the preferences so all assets should be founded.

I'm going to open a bug entry for the merge function.

Cheers,
Manuel

Yep, I'm saw the version hints. Yet, getting down to R20 already means a lot to me. Having learned to read during this communication even more so. So, thanks for teaching me this, as well as for pointing me to GetAllAssets().

The merge is not only to render the document. It's a pretty fundamental thing in this plugin. And we had an eye on the tex folders in prefs as well. 🙂 But in earlier versions, there were only ten folder entries there and we can not rely on the user not using these.

Hello @a_block,

without further questions or postings, we will consider this topic as solved by Wednesday and flag it accordingly.

Thank you for your understanding,
Ferdinand

Thank you Andreas for closing it.

Cheers,
Ferdinand