Here is a handy Cinema 4D Python Script that adds cloner index number as prefix to children’s names.
Python
# Cinema 4D 2025 — Rename Cloner's child objects by prefixing their index
# - Works on the source children under the Cloner (NOT the generated clones)
# - Options at the top for start index, delimiter, stripping old numeric prefixes, and zero-padding
import c4d
import re
# ========== OPTIONS ==========
START_AT = 0 # 0 or 1
DELIM = "_" # e.g. "_", "-", " "
STRIP_OLD_PREFIX = True # If True, remove leading "number + sep" like "12_Name", "001-Name", "3 Name"
AUTO_PAD = True # If True, auto zero-pad to width based on number of children. Example: 001_, 002_, ...
PAD_WIDTH = 0 # Used only if AUTO_PAD == False. Set 0 for no padding, or e.g. 2/3 for 01_/001_
INCLUDE_DESCENDANTS = False # False = rename ONLY direct children of the Cloner; True = rename all descendants in depth-first order
# =============================
CLONER_IDS = {1018544} # Cloner object type ID. You can add more IDs if needed.
def strip_numeric_prefix(name: str) -> str:
# Remove leading "digits + separator + optional whitespace"
# Matches: "12_Name", "001-Name", "3 Name", "7.Name"
return re.sub(r'^\s*\d+\s*[-_\. ]\s*', '', name, count=1)
def iter_direct_children(op: c4d.BaseObject):
child = op.GetDown()
while child:
yield child
child = child.GetNext()
def iter_descendants_dfs(op: c4d.BaseObject):
# Depth-first traversal of descendants
stack = []
child = op.GetDown()
while child:
stack.append(child)
child = child.GetNext()
while stack:
current = stack.pop(0)
yield current
c = current.GetDown()
while c:
stack.append(c)
c = c.GetNext()
def collect_targets(cloner: c4d.BaseObject, include_descendants: bool):
return list(iter_descendants_dfs(cloner)) if include_descendants else list(iter_direct_children(cloner))
def format_index(i: int, width: int) -> str:
return f"{i:0{width}d}" if width > 0 else str(i)
def rename_children_of_cloner(doc: c4d.documents.BaseDocument, cloner: c4d.BaseObject) -> int:
targets = collect_targets(cloner, INCLUDE_DESCENDANTS)
if not targets:
return 0
# Determine padding
if AUTO_PAD:
max_index = START_AT + len(targets) - 1
width = len(str(max_index)) if max_index >= 0 else 1
else:
width = max(0, int(PAD_WIDTH))
renamed = 0
doc.StartUndo()
try:
for idx, obj in enumerate(targets):
base_name = obj.GetName()
if STRIP_OLD_PREFIX:
base_name = strip_numeric_prefix(base_name)
new_index = START_AT + idx
new_name = f"{format_index(new_index, width)}{DELIM}{base_name}"
if new_name != obj.GetName():
doc.AddUndo(c4d.UNDOTYPE_CHANGE, obj)
obj.SetName(new_name)
renamed += 1
finally:
doc.EndUndo()
return renamed
def main():
doc = c4d.documents.GetActiveDocument()
if not doc:
return
selection = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_SELECTIONORDER)
if not selection:
c4d.gui.MessageDialog("Please select at least one Cloner.")
return
total_renamed = 0
processed = 0
for obj in selection:
if obj.GetType() not in CLONER_IDS:
# If you want to allow any object, comment the next two lines:
# continue
pass # Allow renaming children under any selected object if desired
renamed = rename_children_of_cloner(doc, obj)
processed += 1
total_renamed += renamed
print(f"[{obj.GetName()}] Renamed {renamed} object(s) under this cloner.")
if processed == 0:
c4d.gui.MessageDialog("No Cloner objects in selection.")
return
c4d.EventAdd()
c4d.gui.MessageDialog(f"Done. Renamed {total_renamed} object(s) under {processed} selected object(s).")
if __name__ == "__main__":
main()