Solved Python Effectors

Hi everyone,

I've made a simply python effector that allows me to manipulate the color of a effected cloner. That works fine but when I creat an instance of that object and start moving it in 3D space, I get a ton of these errors:

Traceback (most recent call last):
File "'<Python>'", line 18, in main
TypeError: object of type 'NoneType' has no len()

https://www.dropbox.com/s/4cui1f7t8a1l0n9/PyEffectorTest_v1.c4d?dl=0

import c4d
from c4d.modules import mograph as mo
#Welcome to the world of Python

def main():
    linked = op[c4d.ID_USERDATA,1]
    md = mo.GeGetMoData(op)
    md2 = mo.GeGetMoData(linked)
    EB = op[c4d.ID_USERDATA,2]

    if md is None: return False
    
    cnt = md.GetCount()
    clr = md.GetArray(c4d.MODATA_COLOR)
    clr2 = md2.GetArray(c4d.MODATA_COLOR)    

    if cnt > 0: 
        print cnt
    
    #for i in xrange(0,cnt):
        #clr[i] = clr2[i] + (clr2[i] * c4d.Vector(EB))
    
    md.SetArray(c4d.MODATA_COLOR, clr, True)
    return True


    c4d.EventAdd()
    
    

if __name__=='__main__':
    main()

Does anyone have an idea how to get around this?

Took a second look. It seems that you're trying to iterate on a list that doesn't exist. xrange(0,0) returns None not []. This likely happens because the instanced effector can't access the MoData of the other cloner that's been instanced (or something like that). I've taken the liberty of reworking your code to be a bit more error-tolerant:

import c4d
from c4d.modules import mograph as mo

def main():
    # Retrieve User Inputs
    EB = op[c4d.ID_USERDATA,2]
    linked = op[c4d.ID_USERDATA,1]
    if linked is None:
        return True
    
    md = mo.GeGetMoData(op)
    if md is None:
        return True
    
    linked_md = mo.GeGetMoData(linked)
    if linked_md is None:
        return True
    
    md_count = md.GetCount()
    if not md_count:
        return True
    
    linked_md_count = linked_md.GetCount()
    if not linked_md_count:
        return True
    
    # If counts don't match between cloners, use the smaller number.
    clone_count = min([md_count, linked_md_count])
    
    colors = md.GetArray(c4d.MODATA_COLOR)
    if colors is None:
        return
    
    linked_colors = linked_md.GetArray(c4d.MODATA_COLOR)
    if linked_colors is None:
        return

    for i in xrange(clone_count):
        colors[i] = linked_colors[i] + (linked_colors[i] * c4d.Vector(EB))
    
    md.SetArray(c4d.MODATA_COLOR, colors, True)
    return True
    

if __name__=='__main__':
    main()

But looking at your scene I'm not sure you'll get the result you want trying to colorize one cloner with a cloner object it's cloning.

This post is deleted!

Took a second look. It seems that you're trying to iterate on a list that doesn't exist. xrange(0,0) returns None not []. This likely happens because the instanced effector can't access the MoData of the other cloner that's been instanced (or something like that). I've taken the liberty of reworking your code to be a bit more error-tolerant:

import c4d
from c4d.modules import mograph as mo

def main():
    # Retrieve User Inputs
    EB = op[c4d.ID_USERDATA,2]
    linked = op[c4d.ID_USERDATA,1]
    if linked is None:
        return True
    
    md = mo.GeGetMoData(op)
    if md is None:
        return True
    
    linked_md = mo.GeGetMoData(linked)
    if linked_md is None:
        return True
    
    md_count = md.GetCount()
    if not md_count:
        return True
    
    linked_md_count = linked_md.GetCount()
    if not linked_md_count:
        return True
    
    # If counts don't match between cloners, use the smaller number.
    clone_count = min([md_count, linked_md_count])
    
    colors = md.GetArray(c4d.MODATA_COLOR)
    if colors is None:
        return
    
    linked_colors = linked_md.GetArray(c4d.MODATA_COLOR)
    if linked_colors is None:
        return

    for i in xrange(clone_count):
        colors[i] = linked_colors[i] + (linked_colors[i] * c4d.Vector(EB))
    
    md.SetArray(c4d.MODATA_COLOR, colors, True)
    return True
    

if __name__=='__main__':
    main()

But looking at your scene I'm not sure you'll get the result you want trying to colorize one cloner with a cloner object it's cloning.

I have moved this thread to "Cinema 4D Development" category.

Thanks dskeith, that code worked perfectly. Thanks for that!