So I really wanted to get this mandatory requirement nailed before submitting my tool to the asset store. This is the last step in my development process and not something I have worked with before and so I just realized how slow this makes my tool function now…
This is not cool at all … If I build a dense voxel character , the debug Game object in the scene could have over 8000 gameobjects with mesh etc…
So before implementing undo I could change colors or whatever in a spit second. Now that I added the lines of code to support undo it takes forever… and the system is overloaded while performing all this undo registering for many objects
And even worse is there is no progress handler for undo operations either, very very not cool … I could imagine a novice user thinking the Unity application has crashed and just force close it without knowing it was actually busy trying to undo 1000’s of objects.
After this experience im not to keen on this mandatory requirement.
Surely there should be some room for non 100% compliance based on the actual functionality of the tool?
I have never gotten a clear answer from Unity as to where exactly they draw the line in terms of what kinds of operations absolutely must be undoable or what kind of tools are allowed without an undo. I have some asset store tools that don’t have any undo feature, but they’re custom inspectors and don’t really make many if any changes to the scene. But for a new tool I’m making I change stuff in the scene and could see that modifying visible objects really called for an undo make it friendly to use. This is the first time I’ve worked with the undo system and I know Unity just changed the whole undo system in 4.3… previously you had to make huge saves but now it is more of a delta-based thing where you can tell it to just save specific objects or specific variables etc… So try to minimize how much stuff needs to get saved if you can. I think there may also be a way to merge several undos into a single undo step if that helps. It sounds like in your case you’re editing a large collection of objects somehow all tied together and you’re saving the entire collection every time? Can you not just register saves on only the objects that are modified?
Undo the parametric modifiers parameters rather than the objects it generates/modifies. The result is the same, the speed and memory footprint is the gain.
If you are using a non persistent tool to modify objects then you must be more economical with your undos and the data you pick to store, only store once per modification rather than for every refresh or update, minimize what’s stored etc. You may prefer to store a single modifier object/instruction with a custom representation of what’s changed (selection and parameter) in scene that deletes itself after execution.
The new Undo system is a pain. Why the heck are we forced to delete objects through the Undo system? This makes it impossible to use a single API for runtime and editor.
eg… I have a serializedProperty for my vertex colors of the Objects in the scene. When this property is changed I trigger additional code to update the colors array of the mesh on the mesh filter.
This is why I have to add additional calls to undo , so it can revert the property as well as the mesh state when performing an undo.
If there was some cleaver way to know when and what undo operation was performed it would be possible to just rely on the serializedProperty as been the only stored value.
Since I posted I decided to wrap all calls to unity’s undo system with conditionals and a flag and exposed the flag in the inspector . So by default I have fulfilled the requirements and by extension it can be switched off by the user to make the tool function fast like it should.
Yes I wish there was more in depth information concerning this as my tool never destroys anything and any operation can be corrected by executing the same operation with the previous value.
I am learning much about the undo system in the process … I did watch some of the unite 20013 videos and saw they made mention of having revamped much in this area … I will need to go read up on it although Im planning to release the tool without 4.3 suppport for now
Being able to correct something by “executing the same operation with the previous value” is irrelevant to the user, though. Bit it should mean that you can do exactly what Per and I suggested without too much drama.
For example, I have a scene with 10,000 cubes in it of different colours via material colouring, and I run a script that changes all of the colours to some specified value. The fact that I can undo it by running the same function with the previous parameters doesn’t help me at all if I want to go back, because for starters I’d somehow have to know what colour each of the 10,000 cubes were to be able to put them back. Even if there were only two or three colours, and thus I only need two or three calls, and I knew which colours mapped to which objects, just making the selections as a user is going to be a pain in the backside.
Computers, however, are good at that. Creating your own custom undo handler for the above based solely on the parameters shouldn’t be too big an ask. Create a Dictionary linking object references to colour values. For each object in the selection, store the current colour value. When undoing, simply iterate over all entries and set the colour value to the one stored for that key.
For bonus points, use colours as the keys and store List<>s of objects that had that colour, since this will mean you can re-apply it with fewer operations. (The list of object references becomes the selection list for that colour, so you change selection per colour instead of per object and apply the changes in batches.)
Yes it would be possible to roll your own undo system with some Arrays/Lists for the properties and again for some sort of Update Commands System so you can specifically know what operation to preform etc…
My biggest issue here is no *reliable hooks into the Unity undo system because you would still like the user to be able to use the menus or shortcut keys and also that unity can handle selections…
Having looked online and in the documents this is all there is to hook in manually :
The older way was :
if (Event.current.type == EventType.ValidateCommand){
if(Event.current.commandName == "UndoRedoPerformed") {
}
}
and lately unity exposed a delegate or Event with the same name “Undo.undoRedoPerformed” with absolutely no description in the documents for it.
Either way I’m staring at this code and wondering how the heck must you know if it was an “Undo” or a “Redo” when both use the same event??? How would you ever know to move the index for the custom stored values forward or backward?