public override SceneGraphNode Duplicate(out IUndoAction undoAction) { var actor = (Spline)_node.Actor; int newIndex; float newTime; if (Index == actor.SplinePointsCount - 1) { // Append to the end newIndex = actor.SplinePointsCount; newTime = actor.GetSplineTime(newIndex - 1) + 1.0f; } else { // Insert between this and next point newIndex = Index + 1; newTime = (actor.GetSplineTime(Index) + actor.GetSplineTime(Index + 1)) * 0.5f; } var action = new DuplicateUndoAction { SplineId = actor.ID, Index = newIndex, Time = newTime, Value = actor.GetSplineLocalTransform(Index), }; actor.InsertSplineLocalPoint(newIndex, newTime, action.Value); undoAction = action; var splineNode = (SplineNode)SceneGraphFactory.FindNode(action.SplineId); splineNode.OnUpdate(); OnSplineEdited(actor); return(splineNode.ActorChildNodes[newIndex]); }
/// <summary> /// Creates the removed objects (from data). /// </summary> protected virtual void Create() { // Restore objects var actors = Actor.FromBytes(_data); if (actors == null) { return; } for (int i = 0; i < actors.Length; i++) { Guid prefabId = _prefabIds[i]; if (prefabId != Guid.Empty) { Actor.Internal_LinkPrefab(actors[i].unmanagedPtr, ref prefabId, ref _prefabObjectIds[i]); } } var actorNodes = new List <ActorNode>(actors.Length); for (int i = 0; i < actors.Length; i++) { var foundNode = SceneGraphFactory.FindNode(actors[i].ID); if (foundNode is ActorNode node) { actorNodes.Add(node); } } actorNodes.BuildNodesParents(_nodeParents); for (int i = 0; i < _nodeParents.Count; i++) { Editor.Instance.Scene.MarkSceneEdited(_nodeParents[i].ParentScene); } }
private void Create() { // Restore objects var actors = Actor.FromBytes(_data); if (actors == null) { return; } var actorNodes = new List <ActorNode>(actors.Length); for (int i = 0; i < actors.Length; i++) { var foundNode = SceneGraphFactory.FindNode(actors[i].ID); if (foundNode is ActorNode node) { actorNodes.Add(node); } } actorNodes.BuildNodesParents(_nodeParents); for (int i = 0; i < _nodeParents.Count; i++) { Editor.Instance.Scene.MarkSceneEdited(_nodeParents[i].ParentScene); } }
/// <inheritdoc /> public override void Undo() { var nodes = _nodeParents.ToArray(); for (int i = 0; i < nodes.Length; i++) { var node = SceneGraphFactory.FindNode(_nodeParents[i]); if (node != null) { // Unlink nodes from parents (actors spawned for prefab editing are not in a gameplay and may not send some important events) if (node is ActorNode actorNode) { actorNode.Actor.Parent = null; } // Remove objects node.Delete(); // Remove nodes (actors in prefab are not in a gameplay and some events from the engine may not be send eg. ActorDeleted) node.Dispose(); } } _nodeParents.Clear(); }
/// <summary> /// Spawns the specified actor. /// </summary> /// <param name="actor">The actor.</param> /// <param name="parent">The parent.</param> public void Spawn(Actor actor, Actor parent) { if (actor == null) { throw new ArgumentNullException(nameof(actor)); } // Link it actor.Parent = parent ?? throw new ArgumentNullException(nameof(parent)); // Peek spawned node var actorNode = SceneGraphFactory.FindNode(actor.ID) as ActorNode ?? SceneGraphFactory.BuildActorNode(actor); if (actorNode == null) { throw new InvalidOperationException("Failed to create scene node for the spawned actor."); } var parentNode = SceneGraphFactory.FindNode(parent.ID) as ActorNode; actorNode.ParentNode = parentNode ?? throw new InvalidOperationException("Missing scene graph node for the spawned parent actor."); // Call post spawn action (can possibly setup custom default values) actorNode.PostSpawn(); // Create undo action var action = new CustomDeleteActorsAction(new List <SceneGraphNode>(1) { actorNode }, true); Undo.AddAction(action); }
/// <inheritdoc /> public override object ReadJson(JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) { if (reader.TokenType == JsonToken.String) { var id = Guid.Parse((string)reader.Value); return(SceneGraphFactory.FindNode(id)); } return(null); }
/// <summary> /// Gets the actor node. /// </summary> /// <param name="actor">The actor.</param> /// <returns>Found actor node or null if missing. Actor may not be linked to the scene tree so node won't be found in that case.</returns> public ActorNode GetActorNode(Actor actor) { if (actor == null) { return(null); } // ActorNode has the same ID as actor does return(SceneGraphFactory.FindNode(actor.ID) as ActorNode); }
/// <inheritdoc /> public void Undo() { // Remove objects for (int i = 0; i < _nodeParents.Count; i++) { var node = SceneGraphFactory.FindNode(_nodeParents[i]); Editor.Instance.Scene.MarkSceneEdited(node.ParentScene); node.Delete(); } _nodeParents.Clear(); }
public static SceneGraphNode Create(StateData state) { var data = JsonSerializer.Deserialize <Data>(state.State); var spline = Object.Find <Spline>(ref data.Spline); spline.InsertSplineLocalPoint(data.Index, data.Keyframe.Time, data.Keyframe.Value, false); spline.SetSplineKeyframe(data.Index, data.Keyframe); var splineNode = (SplineNode)SceneGraphFactory.FindNode(data.Spline); if (splineNode == null) { return(null); } splineNode.OnUpdate(); OnSplineEdited(spline); return(splineNode.ActorChildNodes[data.Index]); }
private void RemoveBone(string name) { var ragdoll = (Ragdoll)Values[0]; var bodies = ragdoll.Children.Where(x => x is RigidBody && x.IsActive); var joints = bodies.SelectMany(y => y.Children).Where(z => z is Joint && z.IsActive).Cast <Joint>(); var body = bodies.First(x => x.Name == name); var replacementJoint = joints.FirstOrDefault(x => x.Parent == body && x.Target != null); // Fix joints using this bone foreach (var joint in joints) { if (joint.Target == body) { if (replacementJoint != null) { // Swap the joint target to the parent of the removed body to keep ragdoll connected using (new UndoBlock(Presenter.Undo, joint, "Fix joint")) { joint.Target = replacementJoint.Target; joint.EnableAutoAnchor = true; } } else { // Remove joint that will no longer be valid var action = new Actions.DeleteActorsAction(new List <SceneGraphNode> { SceneGraphFactory.FindNode(joint.ID) }); action.Do(); Presenter.Undo?.AddAction(action); } } } // Remove body { var action = new Actions.DeleteActorsAction(new List <SceneGraphNode> { SceneGraphFactory.FindNode(body.ID) }); action.Do(); Presenter.Undo?.AddAction(action); } }
private void RebuildBone(string name) { var ragdoll = (Ragdoll)Values[0]; var animatedModel = (AnimatedModel)ragdoll.Parent; // Remove existing body var bodies = ragdoll.Children.Where(x => x is RigidBody && x.IsActive); var body = bodies.FirstOrDefault(x => x.Name == name); if (body != null) { var action = new Actions.DeleteActorsAction(new List <SceneGraphNode> { SceneGraphFactory.FindNode(body.ID) }); action.Do(); Presenter.Undo?.AddAction(action); } // Build ragdoll SceneGraph.Actors.AnimatedModelNode.BuildRagdoll(animatedModel, new AnimatedModelNode.RebuildOptions(), ragdoll, name); }
private void Select(IEnumerable <Actor> list) { var selection = new List <SceneGraphNode>(); foreach (var e in list) { var node = SceneGraphFactory.FindNode(e.ID); if (node != null) { selection.Add(node); } } if (Presenter.Owner is Windows.PropertiesWindow propertiesWindow) { propertiesWindow.Editor.SceneEditing.Select(selection); } else if (Presenter.Owner is Windows.Assets.PrefabWindow prefabWindow) { prefabWindow.Select(selection); } }
private void Rebuild(AnimatedModelNode.RebuildOptions options) { var ragdoll = (Ragdoll)Values[0]; var animatedModel = (AnimatedModel)ragdoll.Parent; // Remove existing bodies var bodies = ragdoll.Children.Where(x => x is RigidBody && x.IsActive); var actions = new List <IUndoAction>(); foreach (var body in bodies) { var action = new Actions.DeleteActorsAction(new List <SceneGraphNode> { SceneGraphFactory.FindNode(body.ID) }); action.Do(); actions.Add(action); } Presenter.Undo?.AddAction(new MultiUndoAction(actions)); // Build ragdoll SceneGraph.Actors.AnimatedModelNode.BuildRagdoll(animatedModel, options, ragdoll); }
/// <summary> /// Restores selection. /// </summary> public void Restore() { if (_objects.Count == 0) { Editor.Instance.SceneEditing.Deselect(); return; } var selection = new List <SceneGraph.SceneGraphNode>(_objects.Count); for (int i = 0; i < _objects.Count; i++) { var id = _objects[i]; var node = SceneGraphFactory.FindNode(id); if (node != null) { selection.Add(node); } } _objects.Clear(); Editor.Instance.SceneEditing.Select(selection); }
/// <summary> /// Gets the node. /// </summary> /// <param name="id">The actor id.</param> /// <returns>The scene graph node.</returns> protected virtual SceneGraphNode GetNode(Guid id) { return(SceneGraphFactory.FindNode(id)); }
/// <summary> /// Performs the paste/duplicate action and outputs created objects nodes. /// </summary> /// <param name="nodes">The nodes.</param> /// <param name="nodeParents">The node parents.</param> public void Do(out List <ActorNode> nodes, out List <ActorNode> nodeParents) { // Restore objects var actors = Actor.FromBytes(_data, _idsMapping); if (actors == null) { nodes = null; nodeParents = null; return; } nodes = new List <ActorNode>(actors.Length); Scene[] scenes = null; for (int i = 0; i < actors.Length; i++) { var actor = actors[i]; // Check if has no parent linked (broken reference eg. old parent not existing) if (actor.Parent == null) { // Link to the first scene root if (scenes == null) { scenes = SceneManager.Scenes; } actor.SetParent(scenes[0], false); } var foundNode = SceneGraphFactory.FindNode(actor.ID); if (foundNode is ActorNode node) { nodes.Add(node); } } nodeParents = nodes.BuildNodesParents(); // Cache pasted nodes ids (parents only) _nodeParents.Clear(); _nodeParents.Capacity = Mathf.Max(_nodeParents.Capacity, nodeParents.Count); for (int i = 0; i < nodeParents.Count; i++) { _nodeParents.Add(nodeParents[i].ID); } var pasteParentNode = Editor.Instance.Scene.GetActorNode(_pasteParent); if (pasteParentNode != null) { // Move pasted actors to the parent target (if specified and valid) for (int i = 0; i < nodeParents.Count; i++) { nodeParents[i].Actor.SetParent(pasteParentNode.Actor, false); } } for (int i = 0; i < nodeParents.Count; i++) { // Fix name collisions (only for parents) var node = nodeParents[i]; var parent = node.Actor?.Parent; if (parent != null) { string name = node.Name; Actor[] children = parent.GetChildren(); if (children.Count(x => x.Name == name) > 1) { // Generate new name node.Actor.Name = StringUtils.IncrementNameNumber(name, x => children.All(y => y.Name != x)); } } Editor.Instance.Scene.MarkSceneEdited(node.ParentScene); } }
/// <summary> /// Gets the actor node. /// </summary> /// <param name="actorId">The actor id.</param> /// <returns>Found actor node or null if missing. Actor may not be linked to the scene tree so node won't be found in that case.</returns> public ActorNode GetActorNode(Guid actorId) { // ActorNode has the same ID as actor does return(SceneGraphFactory.FindNode(actorId) as ActorNode); }
/// <inheritdoc /> protected override DragDropEffect OnDragDropHeader(DragData data) { var result = DragDropEffect.None; Actor myActor = Actor; Actor newParent; int newOrder = -1; // Check if has no actor (only for Root Actor) if (myActor == null) { // Append to the last scene var scenes = SceneManager.Scenes; if (scenes == null || scenes.Length == 0) { throw new InvalidOperationException("No scene loaded."); } newParent = scenes[scenes.Length - 1]; } else { newParent = myActor; // Use drag positioning to change target parent and index if (_dragOverMode == DragItemPositioning.Above) { if (myActor.HasParent) { newParent = myActor.Parent; newOrder = myActor.OrderInParent; } } else if (_dragOverMode == DragItemPositioning.Below) { if (myActor.HasParent) { newParent = myActor.Parent; newOrder = myActor.OrderInParent + 1; } } } if (newParent == null) { throw new InvalidOperationException("Missing parent actor."); } // Drag actors if (_dragActors != null && _dragActors.HasValidDrag) { bool worldPositionLock = ParentWindow.GetKey(Keys.Control) == false; var singleObject = _dragActors.Objects.Count == 1; if (singleObject) { var targetActor = _dragActors.Objects[0].Actor; using (new UndoBlock(Editor.Instance.Undo, targetActor, "Change actor parent")) { targetActor.SetParent(newParent, worldPositionLock); targetActor.OrderInParent = newOrder; } } else { var targetActors = _dragActors.Objects.ConvertAll(x => x.Actor); using (new UndoMultiBlock(Editor.Instance.Undo, targetActors, "Change actors parent")) { for (int i = 0; i < targetActors.Count; i++) { var targetActor = targetActors[i]; targetActor.SetParent(newParent, worldPositionLock); targetActor.OrderInParent = newOrder; } } } result = DragDropEffect.Move; } // Drag assets else if (_dragAssets != null && _dragAssets.HasValidDrag) { for (int i = 0; i < _dragAssets.Objects.Count; i++) { var item = _dragAssets.Objects[i]; switch (item.ItemDomain) { case ContentDomain.Model: { // Create actor var model = FlaxEngine.Content.LoadAsync <Model>(item.ID); var actor = ModelActor.New(); actor.StaticFlags = Actor.StaticFlags; actor.Name = item.ShortName; actor.Model = model; actor.Transform = Actor.Transform; // Spawn Editor.Instance.SceneEditing.Spawn(actor, Actor); break; } case ContentDomain.Other: { if (item.TypeName == typeof(CollisionData).FullName) { // Create actor var actor = MeshCollider.New(); actor.StaticFlags = Actor.StaticFlags; actor.Name = item.ShortName; actor.CollisionData = FlaxEngine.Content.LoadAsync <CollisionData>(item.ID); actor.Transform = Actor.Transform; // Spawn Editor.Instance.SceneEditing.Spawn(actor, Actor); } break; } case ContentDomain.Audio: { var actor = AudioSource.New(); actor.StaticFlags = Actor.StaticFlags; actor.Name = item.ShortName; actor.Clip = FlaxEngine.Content.LoadAsync <AudioClip>(item.ID); actor.Transform = Actor.Transform; Editor.Instance.SceneEditing.Spawn(actor, Actor); break; } case ContentDomain.Prefab: { throw new NotImplementedException("Spawning prefabs"); } } } result = DragDropEffect.Move; } // Drag actor type else if (_dragActorType != null && _dragActorType.HasValidDrag) { for (int i = 0; i < _dragActorType.Objects.Count; i++) { var item = _dragActorType.Objects[i]; // Create actor var actor = FlaxEngine.Object.New(item) as Actor; if (actor == null) { Editor.LogWarning("Failed to spawn actor of type " + item.FullName); continue; } actor.StaticFlags = Actor.StaticFlags; actor.Name = item.Name; actor.Transform = Actor.Transform; // Spawn Editor.Instance.SceneEditing.Spawn(actor, Actor); } result = DragDropEffect.Move; } // Clear cache _dragActors?.OnDragDrop(); _dragAssets?.OnDragDrop(); _dragActorType?.OnDragDrop(); // Check if scene has been modified if (result != DragDropEffect.None) { var node = SceneGraphFactory.FindNode(newParent.ID) as ActorNode; node?.TreeNode.Expand(); } return(result); }
/// <inheritdoc /> protected override DragDropEffect OnDragDropHeader(DragData data) { var result = DragDropEffect.None; Actor myActor = Actor; Actor newParent; int newOrder = -1; // Check if has no actor (only for Root Actor) if (myActor == null) { // Append to the last scene var scenes = Level.Scenes; if (scenes == null || scenes.Length == 0) { throw new InvalidOperationException("No scene loaded."); } newParent = scenes[scenes.Length - 1]; } else { newParent = myActor; // Use drag positioning to change target parent and index if (DragOverMode == DragItemPositioning.Above) { if (myActor.HasParent) { newParent = myActor.Parent; newOrder = myActor.OrderInParent; } } else if (DragOverMode == DragItemPositioning.Below) { if (myActor.HasParent) { newParent = myActor.Parent; newOrder = myActor.OrderInParent + 1; } } } if (newParent == null) { throw new InvalidOperationException("Missing parent actor."); } // Drag actors if (_dragActors != null && _dragActors.HasValidDrag) { bool worldPositionLock = Root.GetKey(KeyboardKeys.Control) == false; var singleObject = _dragActors.Objects.Count == 1; if (singleObject) { var targetActor = _dragActors.Objects[0].Actor; var customAction = targetActor.HasPrefabLink ? new ReparentAction(targetActor) : null; using (new UndoBlock(ActorNode.Root.Undo, targetActor, "Change actor parent", customAction)) { targetActor.SetParent(newParent, worldPositionLock); targetActor.OrderInParent = newOrder; } } else { var targetActors = _dragActors.Objects.ConvertAll(x => x.Actor); var customAction = targetActors.Any(x => x.HasPrefabLink) ? new ReparentAction(targetActors) : null; using (new UndoMultiBlock(ActorNode.Root.Undo, targetActors, "Change actors parent", customAction)) { for (int i = 0; i < targetActors.Count; i++) { var targetActor = targetActors[i]; targetActor.SetParent(newParent, worldPositionLock); targetActor.OrderInParent = newOrder; } } } result = DragDropEffect.Move; } // Drag assets else if (_dragAssets != null && _dragAssets.HasValidDrag) { for (int i = 0; i < _dragAssets.Objects.Count; i++) { var assetItem = _dragAssets.Objects[i]; if (assetItem.IsOfType <SkinnedModel>()) { // Create actor var model = FlaxEngine.Content.LoadAsync <SkinnedModel>(assetItem.ID); var actor = new AnimatedModel(); actor.StaticFlags = Actor.StaticFlags; actor.Name = assetItem.ShortName; actor.SkinnedModel = model; actor.Transform = Actor.Transform; // Spawn ActorNode.Root.Spawn(actor, Actor); } else if (assetItem.IsOfType <Model>()) { // Create actor var model = FlaxEngine.Content.LoadAsync <Model>(assetItem.ID); var actor = new StaticModel(); actor.StaticFlags = Actor.StaticFlags; actor.Name = assetItem.ShortName; actor.Model = model; actor.Transform = Actor.Transform; // Spawn ActorNode.Root.Spawn(actor, Actor); } else if (assetItem.IsOfType <CollisionData>()) { // Create actor var actor = new MeshCollider(); actor.StaticFlags = Actor.StaticFlags; actor.Name = assetItem.ShortName; actor.CollisionData = FlaxEngine.Content.LoadAsync <CollisionData>(assetItem.ID); actor.Transform = Actor.Transform; // Spawn ActorNode.Root.Spawn(actor, Actor); } else if (assetItem.IsOfType <ParticleSystem>()) { // Create actor var actor = new ParticleEffect(); actor.StaticFlags = Actor.StaticFlags; actor.Name = assetItem.ShortName; actor.ParticleSystem = FlaxEngine.Content.LoadAsync <ParticleSystem>(assetItem.ID); actor.Transform = Actor.Transform; // Spawn ActorNode.Root.Spawn(actor, Actor); } else if (assetItem.IsOfType <SceneAnimation>()) { // Create actor var actor = new SceneAnimationPlayer(); actor.StaticFlags = Actor.StaticFlags; actor.Name = assetItem.ShortName; actor.Animation = FlaxEngine.Content.LoadAsync <SceneAnimation>(assetItem.ID); actor.Transform = Actor.Transform; // Spawn ActorNode.Root.Spawn(actor, Actor); } else if (assetItem.IsOfType <AudioClip>()) { // Create actor var actor = new AudioSource(); actor.StaticFlags = Actor.StaticFlags; actor.Name = assetItem.ShortName; actor.Clip = FlaxEngine.Content.LoadAsync <AudioClip>(assetItem.ID); actor.Transform = Actor.Transform; // Spawn ActorNode.Root.Spawn(actor, Actor); break; } else if (assetItem.IsOfType <Prefab>()) { // Create prefab instance var prefab = FlaxEngine.Content.LoadAsync <Prefab>(assetItem.ID); var actor = PrefabManager.SpawnPrefab(prefab, null); actor.StaticFlags = Actor.StaticFlags; actor.Name = assetItem.ShortName; actor.Transform = Actor.Transform; // Spawn ActorNode.Root.Spawn(actor, Actor); } else if (assetItem is VisualScriptItem visualScriptItem && new ScriptType(typeof(Actor)).IsAssignableFrom(visualScriptItem.ScriptType) && visualScriptItem.ScriptType.CanCreateInstance) { // Create actor var actor = (Actor)visualScriptItem.ScriptType.CreateInstance(); actor.StaticFlags = Actor.StaticFlags; actor.Name = assetItem.ShortName; actor.Transform = Actor.Transform; // Spawn ActorNode.Root.Spawn(actor, Actor); } } result = DragDropEffect.Move; } // Drag actor type else if (_dragActorType != null && _dragActorType.HasValidDrag) { for (int i = 0; i < _dragActorType.Objects.Count; i++) { var item = _dragActorType.Objects[i]; // Create actor var actor = item.CreateInstance() as Actor; if (actor == null) { Editor.LogWarning("Failed to spawn actor of type " + item.TypeName); continue; } actor.StaticFlags = Actor.StaticFlags; actor.Name = item.Name; actor.Transform = Actor.Transform; // Spawn ActorNode.Root.Spawn(actor, Actor); } result = DragDropEffect.Move; } // Clear cache _dragHandlers.OnDragDrop(null); // Check if scene has been modified if (result != DragDropEffect.None) { var node = SceneGraphFactory.FindNode(newParent.ID) as ActorNode; node?.TreeNode.Expand(); } return(result); }