using Ghost.Engine.Core; using Ghost.Entities; using System.Collections.ObjectModel; namespace Ghost.Editor.Core.SceneGraph; /// /// Represents a scene node in the editor scene graph hierarchy. /// Contains editor-only metadata like display name and root entities. /// public class SceneNode { private string _name; private readonly ObservableCollection _rootEntities; /// /// Gets or sets the runtime scene this node represents. /// public Scene Scene { get; set; } /// /// Gets or sets the display name for this scene in the editor. /// This is NOT stored in runtime data. /// public string Name { get => _name; set { _name = value; OnNameChanged?.Invoke(this); } } /// /// Gets or sets the file path where this scene is saved. /// public string? FilePath { get; set; } /// /// Gets or sets whether this scene is currently loaded in the editor. /// public bool IsLoaded { get; set; } /// /// Gets or sets whether this scene has unsaved changes. /// public bool IsDirty { get; set; } /// /// Gets the collection of root entity nodes in this scene. /// public ObservableCollection RootEntities => _rootEntities; /// /// Event raised when the name property changes. /// public event Action? OnNameChanged; /// /// Event raised when root entities collection changes. /// public event Action? OnRootEntitiesChanged; public SceneNode(Scene scene, string name = "New Scene") { Scene = scene; _name = name; _rootEntities = []; _rootEntities.CollectionChanged += (s, e) => OnRootEntitiesChanged?.Invoke(this); } /// /// Adds a root entity node to this scene. /// /// The entity node to add. public void AddRootEntity(EntityNode entityNode) { // Remove from previous parent if any if (entityNode.Parent != null) { entityNode.Parent.RemoveChild(entityNode); } entityNode.Parent = null; entityNode.OwnerScene = this; _rootEntities.Add(entityNode); } /// /// Removes a root entity node from this scene. /// /// The entity node to remove. /// True if the entity was removed, false otherwise. public bool RemoveRootEntity(EntityNode entityNode) { if (_rootEntities.Remove(entityNode)) { entityNode.OwnerScene = null; return true; } return false; } /// /// Gets all entity nodes in this scene (root and descendants) in depth-first order. /// /// An enumerable of all entity nodes in the scene. public IEnumerable GetAllEntities() { foreach (var root in _rootEntities) { yield return root; foreach (var descendant in root.GetAllDescendants()) { yield return descendant; } } } /// /// Finds an entity node by its entity reference. /// /// The entity to search for. /// The entity node if found, null otherwise. public EntityNode? FindNode(Entity entity) { foreach (var root in _rootEntities) { var found = root.FindNode(entity); if (found != null) { return found; } } return null; } /// /// Marks this scene as dirty (has unsaved changes). /// public void MarkDirty() { IsDirty = true; } public override string ToString() { return $"{Name} (Scene ID: {Scene.ID}, Entities: {_rootEntities.Count})"; } }