Hi Guys,
as I'm pretty sure I found a way to achieve what I'm after I thought I update this thread. Maybe this will help others as well.
After taking some time to make NodeData.CopyTo()
work, I ended up not getting it to work at all.
So I thought about how I could achieve what I'm after a different way. Long story short, I ended up implementing a MessageData
plugin as some kind of watchdog for a document. Since its CoreMessage
runs on the main thread I can happily insert and delete materials as much as I wish to. (At least I'm hoping so )
Tl; dr
The idea behind this goes as follows. I have a timer running and in addition to that I listen for c4d.EVMSG_CHANGE
and do some checking to see if the scene needs to update. In my case it's comparing the amount of a specific object against the amount of "specific" materials. If there's a difference I use that difference to delete or insert materials until there's no difference. Once there's no difference I can assign the materials to the objects and let each object control its own material.
To distinguish between materials responsible for my plugin and the ones that aren't I make sure to put a unique plugin id inside the base container of the material I can then check for.
Here's a code snippet of that MessageData
:
class Watchdog(c4d.plugins.MessageData):
PLUGIN_ID = "Use your own unique one"
PLUGIN_NAME = "A MessageData plugin."
PLUGIN_INFO = 0
def __init__(self):
self._time = 1000
def GetTimer(self):
return self._time
def SetTimer(self, time):
self._time = time
@property
def should_execute(self):
is_mainthread = c4d.threading.GeIsMainThread()
check_running = (
bool(c4d.CheckIsRunning(c4d.CHECKISRUNNING_EDITORRENDERING)),
bool(c4d.CheckIsRunning(c4d.CHECKISRUNNING_EXTERNALRENDERING)),
bool(c4d.CheckIsRunning(c4d.CHECKISRUNNING_INTERACTIVERENDERING)),
bool(c4d.CheckIsRunning(c4d.CHECKISRUNNING_ANIMATIONRUNNING)),
bool(c4d.CheckIsRunning(c4d.CHECKISRUNNING_VIEWDRAWING))
)
is_running = any(item is True for item in check_running)
return is_mainthread and not is_running
def CoreMessage(self, mid, mdata):
if not self.should_execute:
return False
doc = c4d.documents.GetActiveDocument()
# SceneHandler is a custom class I delegate the whole creation and comparing stuff to.
objs, mats = ..., ...
scene = SceneHandler(objs, mats)
# Check for a change and start the timer again. But only if the scene should update. Otherwise the timer would run all the time.
if mid == c4d.EVMSG_CHANGE:
if scene.should_update:
self.SetTimer(1000)
# If we get a timer event we update the scene as long as it shouldn't update anymore. We can then stop the timer.
if mid == c4d.MSG_TIMER:
if not scene.should_update:
self.SetTimer(0)
scene.update(doc)
return True
Maybe this will help others. Since I found a solution for my problem this thread can be marked solved.
Cheers,
Sebastian