From 71991ff8c73e5f3c76004a4b4ea35bed3e512be9 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Tue, 3 Jun 2025 15:25:45 -0500 Subject: [PATCH] Show added and removed actors in prefab diff view. --- .../CustomEditors/Dedicated/ActorEditor.cs | 109 +++++++++++++++++- 1 file changed, 107 insertions(+), 2 deletions(-) diff --git a/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs b/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs index 540b602ec..837e7ad3b 100644 --- a/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs @@ -240,6 +240,12 @@ namespace FlaxEditor.CustomEditors.Dedicated node.TextColor = Color.OrangeRed; node.Text = Utilities.Utils.GetPropertyNameUI(removed.PrefabObject.GetType().Name); } + // Removed Actor + else if (editor is RemovedActorDummy removedActor) + { + node.TextColor = Color.OrangeRed; + node.Text = $"{removedActor.PrefabObject.Name} ({Utilities.Utils.GetPropertyNameUI(removedActor.PrefabObject.GetType().Name)})"; + } // Actor or Script else if (editor.Values[0] is SceneObject sceneObject) { @@ -295,11 +301,35 @@ namespace FlaxEditor.CustomEditors.Dedicated // Not used } } + + private class RemovedActorDummy : CustomEditor + { + /// + /// The removed prefab object (from the prefab default instance). + /// + public Actor PrefabObject; + + /// + /// The prefab instance's parent. + /// + public Actor ParentActor; + + /// + /// The order of the removed actor in the parent. + /// + public int OrderInParent; + + /// + public override void Initialize(LayoutElementsContainer layout) + { + // Not used + } + } private TreeNode ProcessDiff(CustomEditor editor, bool skipIfNotModified = true) { - // Special case for new Script added to actor - if (editor.Values[0] is Script script && !script.HasPrefabLink) + // Special case for new Script or child actor added to actor + if ((editor.Values[0] is Script script && !script.HasPrefabLink) || (editor.Values[0] is Actor a && !a.HasPrefabLink)) return CreateDiffNode(editor); // Skip if no change detected @@ -359,6 +389,41 @@ namespace FlaxEditor.CustomEditors.Dedicated } } + // Compare child actors for removed actors. + if (editor is ActorEditor && editor.Values.HasReferenceValue && editor.Values.ReferenceValue is Actor prefabObjectActor) + { + var thisActor = editor.Values[0] as Actor; + for (int i = 0; i < prefabObjectActor.ChildrenCount; i++) + { + var prefabActorChild = prefabObjectActor.Children[i]; + if (thisActor == null) + continue; + bool isRemoved = true; + for (int j = 0; j < thisActor.ChildrenCount; j++) + { + var actorChild = thisActor.Children[j]; + if (actorChild.PrefabObjectID == prefabActorChild.PrefabObjectID) + { + isRemoved = false; + break; + } + } + if (isRemoved) + { + var dummy = new RemovedActorDummy + { + PrefabObject = prefabActorChild, + ParentActor = thisActor, + OrderInParent = prefabActorChild.OrderInParent, + }; + var child = CreateDiffNode(dummy); + if (result == null) + result = CreateDiffNode(editor); + result.AddChild(child); + } + } + } + return result; } @@ -459,6 +524,25 @@ namespace FlaxEditor.CustomEditors.Dedicated return; } + // Special case for reverting removed Actors + if (editor is RemovedActorDummy removedActor) + { + Editor.Log("Reverting removed actor changes to prefab (adding it)"); + + var parentActor = removedActor.ParentActor; + var restored = parentActor.AddChild(removedActor.PrefabObject.GetType()); + var prefabId = parentActor.PrefabID; + var prefabObjectId = removedActor.PrefabObject.PrefabObjectID; + string data = JsonSerializer.Serialize(removedActor.PrefabObject); + JsonSerializer.Deserialize(restored, data); + if (Presenter.Owner is PropertiesWindow propertiesWindow) + Editor.Instance.SceneEditing.Spawn(restored, parentActor, removedActor.OrderInParent); + else if (Presenter.Owner is PrefabWindow prefabWindow) + prefabWindow.Spawn(restored, parentActor, removedActor.OrderInParent); + Actor.Internal_LinkPrefab(FlaxEngine.Object.GetUnmanagedPtr(restored), ref prefabId, ref prefabObjectId); + return; + } + // Special case for new Script added to actor if (editor.Values[0] is Script script && !script.HasPrefabLink) { @@ -470,6 +554,27 @@ namespace FlaxEditor.CustomEditors.Dedicated return; } + + // Special case for new Actor added to actor + if (editor.Values[0] is Actor a && !a.HasPrefabLink) + { + Editor.Log("Reverting added actor changes to prefab (removing it)"); + + // TODO: Keep previous selection. + if (Presenter.Owner is PropertiesWindow propertiesWindow) + { + var editorInstance = Editor.Instance.SceneEditing; + editorInstance.Select(a); + editorInstance.Delete(); + } + else if (Presenter.Owner is PrefabWindow prefabWindow) + { + prefabWindow.Select(prefabWindow.Graph.Root.Find(a)); + prefabWindow.Delete(); + } + + return; + } editor.RevertToReferenceValue(); }