How to copy (and remove) userdata via python ?
-
Hi,
this is what I would like to achieve:
- copy userdata (only one vector element) from object 'b' to object 'a'
- remove all userdata elements from object 'a'
- copy userdata (only one float element) from object 'c' to object 'a'
This is what works so far:
Removing all userdata from object 'a':
for id, bc in aObj.GetUserDataContainer(): aObj.RemoveUserData(id)
Copy userdata from object 'b' to 'a'
for id, bc in bObj.GetUserDataContainer(): aObj.SetUserDataContainer(id,bc)
But here comes the problem: after I copied one userdata element (type: vector) from object 'b' to object 'a', I can't then just remove all userdata from object 'a' and then copy another userdata element (type: float) from object 'c' to (the apparently not entirely cleaned) object 'a'. It seems to me that even after the remove function the previous userdata type is still cached. As a result to this, I get this error when I try to enter any vector data to this userdata element:
TypeError: __setitem__ expected c4d.Vector, not float
When I remove all userdata manually from object 'a' using the GUI it works, but using code like "RemoveUserData" seems to be not the same. In other words: how can I replace a userdata element from type A by another element from type B using python ?
I attached a file for testing:
3 null objects:
object 'b' has float userdata element
object 'c' has vector userdata element
object 'a' is the target objectSelect the python script tag and select the userdata tab. You can run these 3 functions:
- remove all
- b to a (float)
- c to a (vector)
- run function "b to a (float)"
-> float userdata element will be copied to object 'a' - run function "remove all"
-> userdata of object 'a' is gone - run function "c to a (vector)"
-> vector userdata structure is created on object 'a' but vector data can't be set:
TypeError: __setitem__ expected float, not c4d.Vector
- check the userdata of object 'a': the gui shows the vector element but the "c to a" function can't set any vector data (?)
- remove the userdata of object 'a' manually and run function "c to a" again ... this time it works
Really strange. Do I miss any additonal (update-) commands besides "RemoveUserData" in order to really remove any userdata and set new userdata types ?
cheers,
Jens -
My guess is (but I didn't check) that the user data entries on both objects, b and c, have the same ID. Therefore, you're copying the float value first, and then try to overwrite it with a vector. You probably have to check if a user data entry with that ID already exists, and then map the original user data id to a new one.
-
I guess there is a misunderstanding: I'm not only copying the userdata values but the complete structure between the objects. And I'm doing this after I've removed ALL userdata (not only the values) from the target object before ... so there should be no reason for any mismatching types. When I'm doing the removing part manually it's working - so the question is: why is using the python command "RemoveUserData" not the same like just deleting all userdata manually via the GUI ?
- A is a simple null object without any userdata at all
- copy userdata float structure (ID=1) from B to A
(now A has a userdata tab and a userdata float element) - set float element on A (let's say to float value 10.0) ... is working
- removing ALL userdata elements on A (using "RemoveUserData")
(now A should be empty like in step 1). If I check in the GUI there is no userdata anymore, the userdata tab is gone ... but my guess is that the previously existing float element is still cached internally) - copy userdata vector structure (ID=1) from C to A
(this is working and when I check in the GUI there is now a vector element in A's userdata ... BUT internally this element seems to be still a float and not a vector like the GUI is indicating) - trying to set this userdata element to any vector value ... FAILED - caused by type mismatch (??)
Again: the crucial step seems to be step 4). Removing all userdata structure manually via GUI results in no errors. But the python way via "RemoveUserData" caused the error in step 6)
-
Hi @ruckzuck , first of all, I wish you a happy new year!
Regarding your issue, I confirm there is an issue (I'm not sure exactly where it's located right now, either in our RemoveUserData function or either in the [] operator). I will investigate this.
Anyway, use directly SetParameter make it works. I also did a quick rewrite of your code to clean it.
import c4d def removeAll(obj): for id, bc in obj.GetUserDataContainer(): obj.RemoveUserData(id) def copyUserData(src, dst): for id, bc in src.GetUserDataContainer(): dst.SetUserDataContainer(id, bc) dst.SetParameter(id, src[id], c4d.DESCFLAGS_SET_NONE) def main(): a = doc.SearchObject("a") b = doc.SearchObject("b") c = doc.SearchObject("c") if not a or not b or not c: return copyUserData(b, a) removeAll(a) copyUserData(c, a) c4d.EventAdd() # Execute main() if __name__=='__main__': main()
If you have any questions left, please let me know.
Cheers,
Maxime! -
Hi @m_adam, I also wish you a happy new year!
Thanks a lot for your workaround - this is working perfectly
Just one little correction: I guess, it's c4d.DESCFLAGS_SET_0 instead of c4d.DESCFLAGS_SET_NONE
Cheers,
Jens -
No in R20 pretty all symbols were migrated from _0 to _NONE, for compatibility reason in python, _0 keep working as before but should be considered as deprecated.
A note in the documentation will be added and all symbols will be updated for the R20 SP2 documentation
Cheers,
Maxime. -
Ah ok, good to know, thanks for clarifying this - I've tested this in R19 ... but I forgot to mention that, sorry.
-
Seems I also forget to mention but please use About Tags and Tagging like so you can mark a specific version.