diff --git a/Source/Editor/Modules/SceneEditingModule.cs b/Source/Editor/Modules/SceneEditingModule.cs index 78ffd26b0..7827e5003 100644 --- a/Source/Editor/Modules/SceneEditingModule.cs +++ b/Source/Editor/Modules/SceneEditingModule.cs @@ -250,6 +250,84 @@ namespace FlaxEditor.Modules } } + public void Convert(Type to) + { + if (!Editor.SceneEditing.HasSthSelected || !(Editor.SceneEditing.Selection[0] is ActorNode)) + return; + + if (Level.IsAnySceneLoaded == false) + throw new InvalidOperationException("Cannot spawn actor when no scene is loaded."); + + var actionList = new List(); + + Actor old = ((ActorNode)Editor.SceneEditing.Selection[0]).Actor; + Actor actor = (Actor)FlaxEngine.Object.New(to); + + actionList.Add(new SelectionChangeAction(Selection.ToArray(), new SceneGraphNode[0], OnSelectionUndo)); + actionList.Add(new DeleteActorsAction(new List + { + Editor.SceneEditing.Selection[0] + })); + SelectionDeleteBegin?.Invoke(); + actionList[1].Do(); + SelectionDeleteEnd?.Invoke(); + + bool isPlayMode = Editor.StateMachine.IsPlayMode; + + SpawnBegin?.Invoke(); + + actor.Transform = old.Transform; + if (old.Parent != null) + actor.Parent = old.Parent; + actor.StaticFlags = old.StaticFlags; + actor.HideFlags = old.HideFlags; + actor.Layer = old.Layer; + actor.Tag = old.Tag; + actor.Name = old.Name; + actor.IsActive = old.IsActive; + for (var i = old.Children.Length - 1; i >= 0 ; i--) + { + old.Children[i].Parent = actor; + } + + Level.SpawnActor(actor, actor.Parent); + + if (isPlayMode) + actor.StaticFlags = StaticFlags.None; + + var actorNode = Editor.Instance.Scene.GetActorNode(actor); + if (actorNode == null) + throw new InvalidOperationException("Failed to create scene node for the spawned actor."); + + actorNode.PostSpawn(); + Editor.Scene.MarkSceneEdited(actor.Scene); + + actionList.Add(new DeleteActorsAction(new List + { + actorNode + }, true)); + actionList.Add(new SelectionChangeAction(Selection.ToArray(), new SceneGraphNode[]{actorNode}, OnSelectionUndo)); + var actions = new MultiUndoAction(actionList); + Undo.AddAction(actions); + SpawnEnd?.Invoke(); + + var options = Editor.Options.Options; + + // Auto CSG mesh rebuild + if (!isPlayMode && options.General.AutoRebuildCSG) + { + if (actor is BoxBrush && actor.Scene) + actor.Scene.BuildCSG(options.General.AutoRebuildCSGTimeoutMs); + } + + // Auto NavMesh rebuild + if (!isPlayMode && options.General.AutoRebuildNavMesh && actor.Scene && (actor.StaticFlags & StaticFlags.Navigation) == StaticFlags.Navigation) + { + var bounds = actor.BoxWithChildren; + Navigation.BuildNavMesh(actor.Scene, bounds, options.General.AutoRebuildNavMeshTimeoutMs); + } + } + /// /// Deletes the selected objects. Supports undo/redo. /// diff --git a/Source/Editor/Windows/SceneTreeWindow.ContextMenu.cs b/Source/Editor/Windows/SceneTreeWindow.ContextMenu.cs index 87f13b13f..aee456d81 100644 --- a/Source/Editor/Windows/SceneTreeWindow.ContextMenu.cs +++ b/Source/Editor/Windows/SceneTreeWindow.ContextMenu.cs @@ -55,28 +55,30 @@ namespace FlaxEditor.Windows b = contextMenu.AddButton("Duplicate", Editor.SceneEditing.Duplicate); b.Enabled = hasSthSelected; - var convertMenu = contextMenu.AddChildMenu("Convert"); - var convertActorCm = convertMenu.ContextMenu; - for (int i = 0; i < SpawnActorsGroups.Length; i++) + if (Editor.SceneEditing.SelectionCount == 1) { - var group = SpawnActorsGroups[i]; + var convertMenu = contextMenu.AddChildMenu("Convert"); + var convertActorCm = convertMenu.ContextMenu; + for (int i = 0; i < SpawnActorsGroups.Length; i++) + { + var group = SpawnActorsGroups[i]; - if (group.Types.Length == 1) - { - var type = group.Types[0].Value; - convertActorCm.AddButton(group.Types[0].Key, () => Convert(type)); - } - else - { - var groupCm = convertActorCm.AddChildMenu(group.Name).ContextMenu; - for (int j = 0; j < group.Types.Length; j++) + if (group.Types.Length == 1) { - var type = group.Types[j].Value; - groupCm.AddButton(group.Types[j].Key, () => Convert(type)); + var type = group.Types[0].Value; + convertActorCm.AddButton(group.Types[0].Key, () => Editor.SceneEditing.Convert(type)); + } + else + { + var groupCm = convertActorCm.AddChildMenu(group.Name).ContextMenu; + for (int j = 0; j < group.Types.Length; j++) + { + var type = group.Types[j].Value; + groupCm.AddButton(group.Types[j].Key, () => Editor.SceneEditing.Convert(type)); + } } } } - b = contextMenu.AddButton("Delete", Editor.SceneEditing.Delete); b.Enabled = hasSthSelected; diff --git a/Source/Editor/Windows/SceneTreeWindow.cs b/Source/Editor/Windows/SceneTreeWindow.cs index 997f764d2..3db4df799 100644 --- a/Source/Editor/Windows/SceneTreeWindow.cs +++ b/Source/Editor/Windows/SceneTreeWindow.cs @@ -122,30 +122,7 @@ namespace FlaxEditor.Windows // Spawn it Editor.SceneEditing.Spawn(actor, parentActor); } - - private void Convert(Type to) - { - if (!Editor.SceneEditing.HasSthSelected || !(Editor.SceneEditing.Selection[0] is ActorNode)) - return; - Actor old = ((ActorNode)Editor.SceneEditing.Selection[0]).Actor; - Actor actor = (Actor)FlaxEngine.Object.New(to); - actor.Transform = old.Transform; - if (old.Parent != null) - actor.Parent = old.Parent; - actor.StaticFlags = old.StaticFlags; - actor.HideFlags = old.HideFlags; - actor.Layer = old.Layer; - actor.Tag = old.Tag; - actor.Name = old.Name; - actor.IsActive = old.IsActive; - for (var i = old.Children.Length - 1; i >= 0 ; i--) - { - old.Children[i].Parent = actor; - } - Editor.SceneEditing.Delete(); - Editor.SceneEditing.Spawn(actor, actor.Parent); - } - + /// /// Focuses search box. ///