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})";
}
}