@bentraje I am not using Maya so I can't say anything about that. As a programmer though, I know that there ain't nothing like no free launch... uh, lunch. If Maya is able to undo/redo automatically, then the Python API needs to have that functionality built in (automatic call of something like StartUndo at the beginning, EndUndo at the end, and every API call has an AddUndo integrated. That is possible, yes. You have to pay a price for it though, both in development time (of the API programmers) and in execution time. Maybe that is a good tradeoff; I can't judge that. It's certainly easier for the Python programmer
Personally, I admit that I am a lazy pig and often don't integrate any undo in my scripts. But it is not that difficult as you make it sound right now. You would only have to add an AddUndo at points where you really make a change to the object tree (or related internal data). The actual calculations are unaffected. If you have a really complicated script, it would be best if you create it in layers, with the changes made to the object tree being at as high level in the call hierarchy as possible. This allows for safe exits and controlled error situations. (But we're far off topic now.)
No, you would not need to press Ctrl-Z five times. Look at the following:
import c4d
def main():
doc.StartUndo();
obj = doc.GetFirstObject();
doc.AddUndo(c4d.UNDOTYPE_CHANGE_SMALL, obj);
obj.SetName("Renamed!");
obj = obj.GetNext();
doc.AddUndo(c4d.UNDOTYPE_CHANGE_SMALL, obj);
obj.SetName("Renamed!");
obj = obj.GetNext();
doc.AddUndo(c4d.UNDOTYPE_CHANGE_SMALL, obj);
obj.SetName("Renamed!");
obj = obj.GetNext();
doc.AddUndo(c4d.UNDOTYPE_CHANGE_SMALL, obj);
obj.SetName("Renamed!");
obj = obj.GetNext();
doc.AddUndo(c4d.UNDOTYPE_CHANGE_SMALL, obj);
obj.SetName("Renamed!");
doc.EndUndo();
c4d.EventAdd();
if __name__=='__main__':
main()
(warning: If you execute this script you MUST have 5 objects at top level, or the thing will crash.)
Try it, it will rename the objects; one Ctrl-Z is enough to revert all changes.
Now compare this with the following:
import c4d
def main():
doc.StartUndo();
obj = doc.GetFirstObject();
doc.AddUndo(c4d.UNDOTYPE_CHANGE_SMALL, obj);
obj.SetName("Renamed!");
doc.EndUndo();
doc.StartUndo();
obj = obj.GetNext();
doc.AddUndo(c4d.UNDOTYPE_CHANGE_SMALL, obj);
obj.SetName("Renamed!");
doc.EndUndo();
doc.StartUndo();
obj = obj.GetNext();
doc.AddUndo(c4d.UNDOTYPE_CHANGE_SMALL, obj);
obj.SetName("Renamed!");
doc.EndUndo();
doc.StartUndo();
obj = obj.GetNext();
doc.AddUndo(c4d.UNDOTYPE_CHANGE_SMALL, obj);
obj.SetName("Renamed!");
doc.EndUndo();
doc.StartUndo();
obj = obj.GetNext();
doc.AddUndo(c4d.UNDOTYPE_CHANGE_SMALL, obj);
obj.SetName("Renamed!");
doc.EndUndo();
c4d.EventAdd();
if __name__=='__main__':
main()
Here, each AddUndo is encapsulated into a Start/EndUndo block. Now use the script and undo - you will find that each undo only reverts one rename!
So, the Start/EndUndo blocks are the ones that control the "container" that is reverted by Ctrl-Z (as mentioned in my previous post). If you want to revert everything at once, just encapsule the whole execution of the script in the main() function with a Start/EndUndo block. It is not necessary to repeat this block with every method you write.
Now have a look at the following:
import c4d
def main():
doc.StartUndo();
obj = doc.GetFirstObject();
doc.AddUndo(c4d.UNDOTYPE_CHANGE_SMALL, obj);
obj.SetName("Renamed!");
obj = obj.GetNext();
doc.AddUndo(c4d.UNDOTYPE_CHANGE_SMALL, obj);
obj.SetName("Renamed!");
obj = obj.GetNext();
doc.AddUndo(c4d.UNDOTYPE_CHANGE_SMALL, obj);
obj.SetName("Renamed!");
doc.EndUndo();
obj = obj.GetNext();
obj.SetName("Renamed!");
obj = obj.GetNext();
obj.SetName("Renamed!");
c4d.EventAdd();
if __name__=='__main__':
main()
Execute and undo... Ooops! Only three renames were reverted! As obvious from the script, two renames are outside of the Start/EndUndo block and have no AddUndo either, so Ctrl-Z will not affect these.
I leave further exploration to you, but I fear you will not get a super simple undo automation as in Maya.