Hey, so recently discovered that you can no longer just record undo on objects anymore with the new prefab system. Just wanted to get some clarification on best practices with Undo and prefabs.
To perform a simple change and record, I believe this is all you need:
EditorGUI.BeginChangeCheck();
var newValue = EditorGUI.DoSomeGUIControl(targetObject.value);
if (EditorGUI.EndChangeCheck()) {
Undo.RecordObject(targetObject, "Set Value");
targetObject.value = newValue;
PrefabUtility.RecordPrefabInstancePropertyModifications(targetObject);
}
What I don’t understand is do checks need to be put in place to determine if target object is a prefab, prefab instance or non-prefab? It would appear not, but want to make sure.
Also, what about:
Adding child game objects?
Adding components?
Removing child game objects?
Removing components?
And other methods of Undo like:
Undo.RegisterCompleteObjectUndo
Undo.RecordObjects
Undo.RegisterCreatedObjectUndo
Undo.RegisterFullObjectHierarchyUndo
It would seem like there’s a requirement for lots of branching code checking if object is prefab, instance or regular game object, but not sure.
Would be super awesome to get a blog post or something about how to handle Undo with new prefabs. Like comparing the old Undo style with the new. Outlining new approaches to Undo and any possible pitfalls / limitations.
For the most part it’s a non issue, because we can use SerializedObjects. But in some cases you can’t, like modifying objects in OnSceneGUI.
Sorry for reviving, but found this via google search and there’s little info in this.
Well, I’m trying to modify a prefab inside the scene via code at edit-time, and it seems the changes aren’t seen as overrides, and they disappear after reloading the scene from disk.
I’m calling Undo.RegisterFullObjectHierarchyUndo(go),
then I modify some scripts on its children objects, without SerializedObject,
then I call PrefabUtility.RecordPrefabInstancePropertyModifications(go).
The properties get modified in the scene, but they don’t appear as an override
I’m working on a minimalist dependency injection framework, and I register an undo point before attempting to traverse the whole object tree having go as the root.
As you can imagine, this is really intensive. So what you’re saying is that it’s not enough to just call PrefabUtility.RecordPrefabInstancePropertyModifications(go), but I should also call it on each of its components + traverse all its descendants and do the same for them? Maybe I’m missing something.
I could track all the changes, and register them individually but it’s a lot of work because the traverser algorithm can be used at both edit- and runtime, and I’d prefer to avoid additional logic inside it, especially because the prefab stuff is only necessary in editor, and editor performance is cheap (this only happens on a click)
You should only call PrefabUtility.RecordPrefabInstancePropertyModifications(component)after you have changed properties on the component. For undo you record the object before making changes to it.
Hope this helps.
thanks, that clarifies the high-level part. I just wanted to know what to do in case a whole hierarchy of objects was changed, and I don’t know which nodes and which components on those nodes.
would I have to blindly call that PrefabUtility.RecordPrefabInstancePropertyModifications(component) on everything?