172 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			172 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
using System.Collections.Generic;
 | 
						|
 | 
						|
namespace Engine.Core;
 | 
						|
 | 
						|
[System.Diagnostics.DebuggerDisplay("Name: {Name}, Initialized: {Initialized}")]
 | 
						|
public class UniverseObject : BaseEntity, IUniverseObject
 | 
						|
{
 | 
						|
    public Event<IUniverseObject, IUniverseObject.EnteredUniverseArguments> OnEnteredUniverse { get; } = new();
 | 
						|
    public Event<IUniverseObject, IUniverseObject.ExitedUniverseArguments> OnExitedUniverse { get; } = new();
 | 
						|
    public Event<IUniverseObject, IUniverseObject.ParentChangedArguments> OnParentChanged { get; } = new();
 | 
						|
    public Event<IUniverseObject, IUniverseObject.ChildrenAddedArguments> OnChildrenAdded { get; } = new();
 | 
						|
    public Event<IUniverseObject, IUniverseObject.ChildrenRemovedArguments> OnChildrenRemoved { get; } = new();
 | 
						|
 | 
						|
    public Event<IActive, IActive.ActiveChangedArguments> OnActiveChanged { get; } = new();
 | 
						|
    public Event<INameable, INameable.NameChangedArguments> OnNameChanged { get; } = new();
 | 
						|
    public Event<IHasBehaviourController> OnBehaviourControllerAssigned { get; } = new();
 | 
						|
 | 
						|
    private string _name = nameof(UniverseObject);
 | 
						|
    private IUniverse _universe = null!;
 | 
						|
    private IBehaviourController _behaviourController = null!;
 | 
						|
    private bool _isActive = false;
 | 
						|
    private readonly FastList<IUniverseObject> _children = [];
 | 
						|
    private IUniverseObject? _parent = null;
 | 
						|
 | 
						|
    public IReadOnlyList<IUniverseObject> Children => _children;
 | 
						|
    public IBehaviourController BehaviourController => _behaviourController;
 | 
						|
    public IUniverse Universe => _universe;
 | 
						|
    public bool IsInUniverse => _universe is not null;
 | 
						|
    public bool IsActive => _isActive;
 | 
						|
 | 
						|
    public string Name
 | 
						|
    {
 | 
						|
        get => _name;
 | 
						|
        set
 | 
						|
        {
 | 
						|
            if (value == _name) return;
 | 
						|
 | 
						|
            string previousName = _name;
 | 
						|
            _name = value;
 | 
						|
            OnNameChanged?.Invoke(this, new(previousName));
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    public IUniverseObject? Parent
 | 
						|
    {
 | 
						|
        get => _parent;
 | 
						|
        set
 | 
						|
        {
 | 
						|
            if (value == this)
 | 
						|
                throw new Exceptions.AssignFailedException($"{Name} can not parent itself");
 | 
						|
 | 
						|
            if (_parent == value)
 | 
						|
                return;
 | 
						|
 | 
						|
            IUniverseObject? previousParent = Parent;
 | 
						|
            if (previousParent is not null)
 | 
						|
            {
 | 
						|
                previousParent.RemoveChild(this);
 | 
						|
                previousParent.OnActiveChanged.RemoveListener(OnParentActiveChanged);
 | 
						|
            }
 | 
						|
 | 
						|
            _parent = value;
 | 
						|
 | 
						|
            if (value is not null)
 | 
						|
            {
 | 
						|
                if (value.IsInUniverse && !IsInUniverse)
 | 
						|
                    value.Universe.Register(this);
 | 
						|
 | 
						|
                value.AddChild(this);
 | 
						|
                value.OnActiveChanged.AddListener(OnParentActiveChanged);
 | 
						|
            }
 | 
						|
 | 
						|
            UpdateActive();
 | 
						|
            OnParentChanged?.Invoke(this, new(previousParent, value));
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    protected virtual void OnEnteringUniverse(IUniverse universe) { }
 | 
						|
    bool IUniverseObject.EnterUniverse(IUniverse universe)
 | 
						|
    {
 | 
						|
        if (IsInUniverse)
 | 
						|
            return false;
 | 
						|
 | 
						|
        _universe = universe;
 | 
						|
        UpdateActive();
 | 
						|
        OnEnteringUniverse(universe);
 | 
						|
        OnEnteredUniverse?.Invoke(this, new(universe));
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    protected virtual void OnExitingUniverse(IUniverse universe) { }
 | 
						|
    bool IUniverseObject.ExitUniverse()
 | 
						|
    {
 | 
						|
        if (!IsInUniverse || _universe is not IUniverse universe)
 | 
						|
            return false;
 | 
						|
 | 
						|
        OnExitingUniverse(universe);
 | 
						|
        _universe = null!;
 | 
						|
        OnExitedUniverse?.Invoke(this, new(universe));
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    public void AddChild(IUniverseObject child)
 | 
						|
    {
 | 
						|
        if (_children.Contains(child))
 | 
						|
            return;
 | 
						|
 | 
						|
        _children.Add(child);
 | 
						|
        child.Parent = this;
 | 
						|
        OnChildrenAdded?.Invoke(this, new(child));
 | 
						|
    }
 | 
						|
 | 
						|
    public void RemoveChild(IUniverseObject child)
 | 
						|
    {
 | 
						|
        if (!_children.Remove(child))
 | 
						|
            return;
 | 
						|
 | 
						|
        child.Parent = null;
 | 
						|
        OnChildrenRemoved?.Invoke(this, new(child));
 | 
						|
    }
 | 
						|
 | 
						|
    protected virtual void OnAssign(IBehaviourController behaviourController) { }
 | 
						|
    public bool Assign(IBehaviourController behaviourController)
 | 
						|
    {
 | 
						|
        if (IsInitialized)
 | 
						|
            return false;
 | 
						|
 | 
						|
        _behaviourController = behaviourController;
 | 
						|
        OnAssign(behaviourController);
 | 
						|
        OnBehaviourControllerAssigned?.Invoke(this);
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    protected override void OnAssign(IStateEnable stateEnable)
 | 
						|
    {
 | 
						|
        base.OnAssign(stateEnable);
 | 
						|
 | 
						|
        stateEnable.OnEnabledChanged.AddListener(OnStateEnabledChanged);
 | 
						|
        UpdateActive();
 | 
						|
    }
 | 
						|
 | 
						|
    private void OnParentActiveChanged(IActive sender, IActive.ActiveChangedArguments args) => UpdateActive();
 | 
						|
    private void OnStateEnabledChanged(IStateEnable sender, IStateEnable.EnabledChangedArguments args) => UpdateActive();
 | 
						|
 | 
						|
    private void UpdateActive()
 | 
						|
    {
 | 
						|
        bool previousActive = IsActive;
 | 
						|
        _isActive = StateEnable.Enabled && (Parent?.IsActive ?? true);
 | 
						|
 | 
						|
        if (previousActive != IsActive)
 | 
						|
            OnActiveChanged?.Invoke(this, new(previousActive));
 | 
						|
    }
 | 
						|
 | 
						|
    protected override void UnassignInternal()
 | 
						|
    {
 | 
						|
        base.UnassignInternal();
 | 
						|
        StateEnable.OnEnabledChanged.RemoveListener(OnStateEnabledChanged);
 | 
						|
    }
 | 
						|
 | 
						|
    protected override void InitializeInternal()
 | 
						|
    {
 | 
						|
        base.InitializeInternal();
 | 
						|
        _behaviourController ??= Factory.BehaviourControllerFactory.Instantiate(this);
 | 
						|
        _behaviourController.Initialize();
 | 
						|
    }
 | 
						|
 | 
						|
    public UniverseObject()
 | 
						|
    {
 | 
						|
        _name = GetType().Name;
 | 
						|
    }
 | 
						|
}
 |