I hate going back to the layers topic so soon again, but there seems to be something wrong with doc.GetLayerObjectRoot().InsertFirst(layer)
. After executing this function, layer
is no longer alive; the layer list in the layer manager is destroyed, and C4D will crash if you try to access the layers through Python after that - in any form, even with a simple print
.
Try executing this function:
def createLayerSelected():
layer = c4d.documents.LayerObject()
if not layer.IsAlive():
print "Layer not created"
return
if layer == None: return
doc.GetLayerObjectRoot().InsertFirst(layer)
if not layer.IsAlive():
print "Layer not alive after insertion"
return
layer[c4d.ID_BASELIST_NAME] = "New Layer"
layer[c4d.ID_LAYER_COLOR] = c4d.Vector(
random.randint(0,256)/256.0,
random.randint(0,256)/256.0,
random.randint(0,256)/256.0)
layer[c4d.ID_LAYER_SOLO] = False
layer[c4d.ID_LAYER_VIEW] = True
layer[c4d.ID_LAYER_RENDER] = True
layer[c4d.ID_LAYER_MANAGER] = True
layer[c4d.ID_LAYER_ANIMATION] = True
layer[c4d.ID_LAYER_GENERATORS] = True
layer[c4d.ID_LAYER_DEFORMERS] = True
layer[c4d.ID_LAYER_EXPRESSIONS] = True
layer[c4d.ID_LAYER_LOCKED] = False
layer[c4d.ID_LAYER_XREF] = True
if not layer.IsAlive():
print "Layer not alive after attribute setting"
return
doc.AddUndo(c4d.UNDOTYPE_NEW, layer)
if not layer.IsAlive():
print "Layer not alive after AddUndo"
return
# change the layer for all selected objects
for currentObject in walkSelectedObjects():
doc.AddUndo(c4d.UNDOTYPE_CHANGE_SMALL, currentObject)
currentObject.SetLayerObject(layer)
The attribute setting etc pp actually does not matter, as the attempt to insert the new layer causes the trouble already (while the function returns properly, the damage is already done to the layer list).
Compare with the following version, which does not attempt to insert into the GeListHead
but uses a different function to insert before the first existing layer:
def createLayerSelected2():
layer = c4d.documents.LayerObject()
if not layer.IsAlive():
print "Layer not created"
return
if layer == None: return
insLayer = doc.GetLayerObjectRoot().GetFirst()
layer.InsertBefore(insLayer)
if not layer.IsAlive():
print "Layer not alive after insertion"
return
layer[c4d.ID_BASELIST_NAME] = "New Layer"
layer[c4d.ID_LAYER_COLOR] = c4d.Vector(
random.randint(0,256)/256.0,
random.randint(0,256)/256.0,
random.randint(0,256)/256.0)
layer[c4d.ID_LAYER_SOLO] = False
layer[c4d.ID_LAYER_VIEW] = True
layer[c4d.ID_LAYER_RENDER] = True
layer[c4d.ID_LAYER_MANAGER] = True
layer[c4d.ID_LAYER_ANIMATION] = True
layer[c4d.ID_LAYER_GENERATORS] = True
layer[c4d.ID_LAYER_DEFORMERS] = True
layer[c4d.ID_LAYER_EXPRESSIONS] = True
layer[c4d.ID_LAYER_LOCKED] = False
layer[c4d.ID_LAYER_XREF] = True
if not layer.IsAlive():
print "Layer not alive after attribute setting"
return
doc.AddUndo(c4d.UNDOTYPE_NEW, layer)
if not layer.IsAlive():
print "Layer not alive after AddUndo"
return
# change the layer for all selected objects
for currentObject in walkSelectedObjects():
doc.AddUndo(c4d.UNDOTYPE_CHANGE_SMALL, currentObject)
currentObject.SetLayerObject(layer)
Naturally, this will only work when there is a layer already in the doc
's layer list, which makes it unusable as a workaround. (I didn't bother with a None
test here.) But the function works fine, creates the layer, inserts the layer, assigns the layer to the selected objects (sorry, walkSelectedObjects
is missing as a function here, replace with GetActiveObjects
), sets undos properly, and does not encounter errors.
(Yes, I know that this functionality is identical with the built-in function "New Layer from Object Selection".)
My conclusion is that doc.GetLayerObjectRoot().InsertFirst(layer)
is doing some ugly stuff. I have not tried to use InsertFirst
on any other GeListHead
s beyond layers yet, maybe that would yield the same crashes.