Example #1
0
        /// <summary>
        /// Deletes selected objects.
        /// </summary>
        public void Delete()
        {
            // Peek things that can be removed
            var objects = Selection.Where(x => x.CanDelete && x != Graph.Main).ToList().BuildAllNodes().Where(x => x.CanDelete).ToList();

            if (objects.Count == 0)
            {
                return;
            }

            // Change selection
            var action1 = new SelectionChangeAction(Selection.ToArray(), new SceneGraphNode[0], OnSelectionUndo);

            // Delete objects
            var action2 = new CustomDeleteActorsAction(objects);

            // Merge actions and perform them
            var action = new MultiUndoAction(new IUndoAction[]
            {
                action1,
                action2
            }, action2.ActionString);

            action.Do();
            Undo.AddAction(action);
        }
        /// <summary>
        /// Deletes the selected objects. Supports undo/redo.
        /// </summary>
        public void Delete()
        {
            // Peek things that can be removed
            var objects = Selection.Where(x => x.CanDelete).ToList().BuildAllNodes().Where(x => x.CanDelete).ToList();

            if (objects.Count == 0)
            {
                return;
            }

            // Change selection
            var action1 = new SelectionChangeAction(Selection.ToArray(), new SceneGraphNode[0]);

            // Delete objects
            var action2 = new DeleteActorsAction(objects);

            // Merge two actions and perform them
            var action = new MultiUndoAction(new IUndoAction[] { action1, action2 }, action2.ActionString);

            action.Do();
            Undo.AddAction(action);

            // Auto CSG mesh rebuild
            foreach (var obj in objects)
            {
                if (obj is ActorNode node && node.Actor is BoxBrush)
                {
                    node.Actor.Scene.BuildCSG();
                }
            }
        }
Example #3
0
        /// <summary>
        /// Pastes the copied objects. Supports undo/redo.
        /// </summary>
        /// <param name="pasteTargetActor">The target actor to paste copied data.</param>
        public void Paste(Actor pasteTargetActor)
        {
            // Get clipboard data
            var data = Clipboard.RawData;

            // Set paste target if only one actor is selected and no target provided
            if (pasteTargetActor == null && SelectionCount == 1 && Selection[0] is ActorNode actorNode)
            {
                pasteTargetActor = actorNode.Actor;
            }

            // Create paste action
            var pasteAction = PasteActorsAction.Paste(data, pasteTargetActor?.ID ?? Guid.Empty);
            if (pasteAction != null)
            {
                pasteAction.Do(out _, out var nodeParents);

                // Select spawned objects (parents only)
                var selectAction = new SelectionChangeAction(Selection.ToArray(), nodeParents.Cast<SceneGraphNode>().ToArray(), OnSelectionUndo);
                selectAction.Do();

                // Build single compound undo action that pastes the actors and selects the created objects (parents only)
                Undo.AddAction(new MultiUndoAction(pasteAction, selectAction));
                OnSelectionChanged();
            }
        }
Example #4
0
        /// <summary>
        /// Deletes the selected objects. Supports undo/redo.
        /// </summary>
        public void Delete()
        {
            // Peek things that can be removed
            var objects = Selection.Where(x => x.CanDelete).ToList().BuildAllNodes().Where(x => x.CanDelete).ToList();

            if (objects.Count == 0)
            {
                return;
            }

            bool isPlayMode = Editor.StateMachine.IsPlayMode;

            SelectionDeleteBegin?.Invoke();

            // Change selection
            var action1 = new SelectionChangeAction(Selection.ToArray(), new SceneGraphNode[0], OnSelectionUndo);

            // Delete objects
            var action2 = new DeleteActorsAction(objects);

            // Merge two actions and perform them
            var action = new MultiUndoAction(new IUndoAction[]
            {
                action1,
                action2
            }, action2.ActionString);

            action.Do();
            Undo.AddAction(action);

            SelectionDeleteEnd?.Invoke();

            var options = Editor.Options.Options;

            // Auto CSG mesh rebuild
            if (!isPlayMode && options.General.AutoRebuildCSG)
            {
                foreach (var obj in objects)
                {
                    if (obj is ActorNode node && node.Actor is BoxBrush)
                    {
                        node.Actor.Scene.BuildCSG(options.General.AutoRebuildCSGTimeoutMs);
                    }
                }
            }

            // Auto NavMesh rebuild
            if (!isPlayMode && options.General.AutoRebuildNavMesh)
            {
                foreach (var obj in objects)
                {
                    if (obj is ActorNode node && node.Actor.Scene && (node.Actor.StaticFlags & StaticFlags.Navigation) == StaticFlags.Navigation)
                    {
                        var bounds = node.Actor.BoxWithChildren;
                        node.Actor.Scene.BuildNavMesh(bounds, options.General.AutoRebuildNavMeshTimeoutMs);
                    }
                }
            }
        }
		public void FinishSelectionChange()
		{
			Selection.SymmetryMatrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, Vector3.one);
			UpdateSelectionRing();
			if(AllowSymmetry)
				GenerateSymmetry();
			EditMap.MarkerSelectionOptions.UpdateOptions();

			SelectionChangeAction?.Invoke();
		}
Example #6
0
        private void OnPasteAcction(PasteActorsAction pasteAction)
        {
            pasteAction.Do(out _, out var nodeParents);

            // Select spawned objects
            var selectAction = new SelectionChangeAction(Selection.ToArray(), nodeParents.Cast <SceneGraphNode>().ToArray(), OnSelectionUndo);

            selectAction.Do();

            Undo.AddAction(new MultiUndoAction(pasteAction, selectAction));
            OnSelectionChanges();
        }
        /// <summary>
        /// Deletes the selected objects. Supports undo/redo.
        /// </summary>
        public void Delete()
        {
            // Peek things that can be removed
            var objects = Selection.Where(x => x.CanDelete).ToList().BuildAllNodes().Where(x => x.CanDelete).ToList();

            if (objects.Count == 0)
            {
                return;
            }
            var isSceneTreeFocus = Editor.Windows.SceneWin.ContainsFocus;

            SelectionDeleteBegin?.Invoke();

            // Change selection
            var action1 = new SelectionChangeAction(Selection.ToArray(), new SceneGraphNode[0], OnSelectionUndo);

            // Delete objects
            var action2 = new DeleteActorsAction(objects);

            // Merge two actions and perform them
            var action = new MultiUndoAction(new IUndoAction[]
            {
                action1,
                action2
            }, action2.ActionString);

            action.Do();
            Undo.AddAction(action);

            SelectionDeleteEnd?.Invoke();

            OnDirty(objects);

            if (isSceneTreeFocus)
            {
                Editor.Windows.SceneWin.Focus();
            }
        }
Example #8
0
        /// <summary>
        /// Duplicates the selected objects. Supports undo/redo.
        /// </summary>
        public void Duplicate()
        {
            // Peek things that can be copied (copy all actors)
            var nodes = Selection.Where(x => x.CanDuplicate).ToList().BuildAllNodes();
            if (nodes.Count == 0)
                return;
            var actors = new List<Actor>();
            var newSelection = new List<SceneGraphNode>();
            List<IUndoAction> customUndoActions = null;
            foreach (var node in nodes)
            {
                if (node.CanDuplicate)
                {
                    if (node is ActorNode actorNode)
                    {
                        actors.Add(actorNode.Actor);
                    }
                    else
                    {
                        var customDuplicatedObject = node.Duplicate(out var customUndoAction);
                        if (customDuplicatedObject != null)
                            newSelection.Add(customDuplicatedObject);
                        if (customUndoAction != null)
                        {
                            if (customUndoActions == null)
                                customUndoActions = new List<IUndoAction>();
                            customUndoActions.Add(customUndoAction);
                        }
                    }
                }
            }
            if (actors.Count == 0)
            {
                // Duplicate custom scene graph nodes only without actors
                if (newSelection.Count != 0)
                {
                    // Select spawned objects (parents only)
                    var selectAction = new SelectionChangeAction(Selection.ToArray(), newSelection.ToArray(), OnSelectionUndo);
                    selectAction.Do();

                    // Build a single compound undo action that pastes the actors, pastes custom stuff (scene graph extension) and selects the created objects (parents only)
                    var customUndoActionsCount = customUndoActions?.Count ?? 0;
                    var undoActions = new IUndoAction[1 + customUndoActionsCount];
                    for (int i = 0; i < customUndoActionsCount; i++)
                        undoActions[i] = customUndoActions[i];
                    undoActions[undoActions.Length - 1] = selectAction;

                    Undo.AddAction(new MultiUndoAction(undoActions));
                    OnSelectionChanged();
                }
                return;
            }

            // Serialize actors
            var data = Actor.ToBytes(actors.ToArray());
            if (data == null)
            {
                Editor.LogError("Failed to copy actors data.");
                return;
            }

            // Create paste action (with selecting spawned objects)
            var pasteAction = PasteActorsAction.Duplicate(data, Guid.Empty);
            if (pasteAction != null)
            {
                pasteAction.Do(out _, out var nodeParents);

                // Select spawned objects (parents only)
                newSelection.AddRange(nodeParents);
                var selectAction = new SelectionChangeAction(Selection.ToArray(), newSelection.ToArray(), OnSelectionUndo);
                selectAction.Do();

                // Build a single compound undo action that pastes the actors, pastes custom stuff (scene graph extension) and selects the created objects (parents only)
                var customUndoActionsCount = customUndoActions?.Count ?? 0;
                var undoActions = new IUndoAction[2 + customUndoActionsCount];
                undoActions[0] = pasteAction;
                for (int i = 0; i < customUndoActionsCount; i++)
                    undoActions[i + 1] = customUndoActions[i];
                undoActions[undoActions.Length - 1] = selectAction;

                Undo.AddAction(new MultiUndoAction(undoActions));
                OnSelectionChanged();
            }
        }
Example #9
0
        /// <summary>
        /// Converts the selected actor to another type.
        /// </summary>
        /// <param name="to">The type to convert in.</param>
        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 IUndoAction[4];
            Actor old = ((ActorNode)Editor.SceneEditing.Selection[0]).Actor;
            Actor actor = (Actor)FlaxEngine.Object.New(to);
            var parent = old.Parent;
            var orderInParent = old.OrderInParent;

            SelectionDeleteBegin?.Invoke();

            actionList[0] = new SelectionChangeAction(Selection.ToArray(), new SceneGraphNode[0], OnSelectionUndo);
            actionList[0].Do();

            actionList[1] = new DeleteActorsAction(new List<SceneGraphNode>
            {
                Editor.Instance.Scene.GetActorNode(old)
            });
            actionList[1].Do();

            SelectionDeleteEnd?.Invoke();

            SpawnBegin?.Invoke();

            // Copy properties
            actor.Transform = old.Transform;
            actor.StaticFlags = old.StaticFlags;
            actor.HideFlags = old.HideFlags;
            actor.Layer = old.Layer;
            actor.Tag = old.Tag;
            actor.Name = old.Name;
            actor.IsActive = old.IsActive;

            // Spawn actor
            Level.SpawnActor(actor, parent);
            if (parent != null)
                actor.OrderInParent = orderInParent;
            if (Editor.StateMachine.IsPlayMode)
                actor.StaticFlags = StaticFlags.None;

            // Move children
            for (var i = old.ScriptsCount - 1; i >= 0; i--)
            {
                var script = old.Scripts[i];
                script.Actor = actor;
                Guid newid = Guid.NewGuid();
                FlaxEngine.Object.Internal_ChangeID(FlaxEngine.Object.GetUnmanagedPtr(script), ref newid);
            }
            for (var i = old.Children.Length - 1; i >= 0; i--)
            {
                old.Children[i].Parent = actor;
            }

            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[2] = new DeleteActorsAction(new List<SceneGraphNode>
            {
                actorNode
            }, true);

            actionList[3] = new SelectionChangeAction(new SceneGraphNode[0], new SceneGraphNode[] { actorNode }, OnSelectionUndo);
            actionList[3].Do();

            var actions = new MultiUndoAction(actionList);
            Undo.AddAction(actions);

            SpawnEnd?.Invoke();

            OnDirty(actorNode);
        }
Example #10
0
        /// <summary>
        /// Converts the selected actor to another type.
        /// </summary>
        /// <param name="to">The type to convert in.</param>
        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 IUndoAction[4];
            var oldNode       = (ActorNode)Editor.SceneEditing.Selection[0];
            var old           = oldNode.Actor;
            var actor         = (Actor)FlaxEngine.Object.New(to);
            var parent        = old.Parent;
            var orderInParent = old.OrderInParent;

            // Steps:
            // - deselect old actor
            // - destroy old actor
            // - spawn new actor
            // - select new actor

            SelectionDeleteBegin?.Invoke();

            actionList[0] = new SelectionChangeAction(Selection.ToArray(), new SceneGraphNode[0], OnSelectionUndo);
            actionList[0].Do();

            actionList[1] = new DeleteActorsAction(oldNode.BuildAllNodes().Where(x => x.CanDelete).ToList());

            SelectionDeleteEnd?.Invoke();

            SpawnBegin?.Invoke();

            // Copy properties
            actor.Transform   = old.Transform;
            actor.StaticFlags = old.StaticFlags;
            actor.HideFlags   = old.HideFlags;
            actor.Layer       = old.Layer;
            actor.Tag         = old.Tag;
            actor.Name        = old.Name;
            actor.IsActive    = old.IsActive;

            // Spawn actor
            Level.SpawnActor(actor, parent);
            if (parent != null)
            {
                actor.OrderInParent = orderInParent;
            }
            if (Editor.StateMachine.IsPlayMode)
            {
                actor.StaticFlags = StaticFlags.None;
            }

            // Move children
            var scripts = old.Scripts;

            for (var i = scripts.Length - 1; i >= 0; i--)
            {
                scripts[i].Actor = actor;
            }
            var children = old.Children;

            for (var i = children.Length - 1; i >= 0; i--)
            {
                children[i].Parent = actor;
            }

            var actorNode = Editor.Instance.Scene.GetActorNode(actor);

            if (actorNode == null)
            {
                throw new InvalidOperationException("Failed to create scene node for the spawned actor.");
            }
            actorNode.PostConvert(oldNode);

            actorNode.PostSpawn();
            Editor.Scene.MarkSceneEdited(actor.Scene);

            actionList[1].Do();
            actionList[2] = new DeleteActorsAction(actorNode.BuildAllNodes().Where(x => x.CanDelete).ToList(), true);

            actionList[3] = new SelectionChangeAction(new SceneGraphNode[0], new SceneGraphNode[] { actorNode }, OnSelectionUndo);
            actionList[3].Do();

            Undo.AddAction(new MultiUndoAction(actionList, "Convert actor"));

            SpawnEnd?.Invoke();

            OnDirty(actorNode);
        }