167 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			167 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
using System;
 | 
						|
using System.Collections;
 | 
						|
using System.Collections.Generic;
 | 
						|
 | 
						|
namespace Engine.Core;
 | 
						|
 | 
						|
[System.Diagnostics.DebuggerDisplay("UniverseObject Count: {_universeObjects.Count}")]
 | 
						|
public class Universe : BaseEntity, IUniverse
 | 
						|
{
 | 
						|
    public Event<IUniverse, IUniverse.UpdateArguments> OnPreUpdate { get; } = new();
 | 
						|
    public Event<IUniverse, IUniverse.UpdateArguments> OnUpdate { get; } = new();
 | 
						|
    public Event<IUniverse, IUniverse.UpdateArguments> OnPostUpdate { get; } = new();
 | 
						|
    public Event<IUniverse> OnPreDraw { get; } = new();
 | 
						|
    public Event<IUniverse> OnDraw { get; } = new();
 | 
						|
    public Event<IUniverse> OnPostDraw { get; } = new();
 | 
						|
    public Event<IUniverse, IUniverse.UniverseObjectRegisteredArguments> OnPreUniverseObjectRegistered { get; } = new();
 | 
						|
    public Event<IUniverse, IUniverse.UniverseObjectRegisteredArguments> OnUniverseObjectRegistered { get; } = new();
 | 
						|
    public Event<IUniverse, IUniverse.UniverseObjectUnRegisteredArguments> OnPreUniverseObjectUnRegistered { get; } = new();
 | 
						|
    public Event<IUniverse, IUniverse.UniverseObjectUnRegisteredArguments> OnUniverseObjectUnRegistered { get; } = new();
 | 
						|
    public Event<IUniverse, IUniverse.TimeScaleChangedArguments> OnTimeScaleChanged { get; } = new();
 | 
						|
 | 
						|
    private readonly Event<IInitializable>.EventHandler delegateOnUniverseObjectFinalize = null!;
 | 
						|
    private readonly Event<IUniverseObject, IUniverseObject.ExitedUniverseArguments>.EventHandler delegateOnUniverseObjectExitedUniverse = null!;
 | 
						|
 | 
						|
    private readonly FastList<IUniverseObject> _universeObjects = new(Constants.UNIVERSE_OBJECTS_SIZE_INITIAL);
 | 
						|
    private float _timeScale = 1f;
 | 
						|
 | 
						|
    public Universe()
 | 
						|
    {
 | 
						|
        delegateOnUniverseObjectFinalize = OnUniverseObjectFinalize;
 | 
						|
        delegateOnUniverseObjectExitedUniverse = OnUniverseObjectExitedUniverse;
 | 
						|
    }
 | 
						|
 | 
						|
    public IUniverseObject Root { get; private set; } = Factory.UniverseObjectFactory.Instantiate().SetUniverseObject("Root");
 | 
						|
 | 
						|
    public UniverseTime Time { get; private set; } = new();
 | 
						|
    public UniverseTime UnscaledTime { get; private set; } = new();
 | 
						|
    public float TimeScale
 | 
						|
    {
 | 
						|
        get => _timeScale;
 | 
						|
        set
 | 
						|
        {
 | 
						|
            value = value.Max(0f);
 | 
						|
            if (value == _timeScale)
 | 
						|
                return;
 | 
						|
 | 
						|
            float previousTimeScale = _timeScale;
 | 
						|
            _timeScale = value;
 | 
						|
            OnTimeScaleChanged?.Invoke(this, new(previousTimeScale));
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    public void Register(IUniverseObject universeObject)
 | 
						|
    {
 | 
						|
        if (_universeObjects.Contains(universeObject))
 | 
						|
            throw new Exception($"{nameof(IUniverseObject)} named {universeObject.Name} is already registered to the {nameof(Universe)}.");
 | 
						|
 | 
						|
        OnPreUniverseObjectRegistered?.Invoke(this, new(universeObject));
 | 
						|
 | 
						|
        universeObject.OnFinalized.AddListener(delegateOnUniverseObjectFinalize);
 | 
						|
        universeObject.OnExitedUniverse.AddListener(delegateOnUniverseObjectExitedUniverse);
 | 
						|
 | 
						|
        if (!universeObject.Initialize())
 | 
						|
            throw new Exception($"{universeObject.Name} can't be initialized");
 | 
						|
 | 
						|
        if (universeObject.Parent == null)
 | 
						|
            universeObject.Parent = Root;
 | 
						|
 | 
						|
        _universeObjects.Add(universeObject);
 | 
						|
 | 
						|
        if (!universeObject.EnterUniverse(this))
 | 
						|
            throw new Exception($"{universeObject.Name} can't enter the universe");
 | 
						|
 | 
						|
        for (int i = 0; i < universeObject.Children.Count; i++)
 | 
						|
            Register(universeObject.Children[i]);
 | 
						|
 | 
						|
        OnUniverseObjectRegistered?.Invoke(this, new(universeObject));
 | 
						|
    }
 | 
						|
 | 
						|
    public T InstantiateUniverseObject<T>(params object?[]? args) where T : class, IUniverseObject
 | 
						|
    {
 | 
						|
        T universeObject = Factory.UniverseObjectFactory.Instantiate<T>(args);
 | 
						|
        Register(universeObject);
 | 
						|
        return universeObject;
 | 
						|
    }
 | 
						|
 | 
						|
    public void Remove(IUniverseObject universeObject)
 | 
						|
    {
 | 
						|
        universeObject.Parent = null;
 | 
						|
        RemoveIncursive(universeObject);
 | 
						|
    }
 | 
						|
 | 
						|
    private void RemoveIncursive(IUniverseObject universeObject)
 | 
						|
    {
 | 
						|
        if (!_universeObjects.Contains(universeObject))
 | 
						|
            throw new Exception($"{nameof(IUniverseObject)} named {universeObject.Name} is not registered to the {nameof(Universe)}.");
 | 
						|
 | 
						|
        OnPreUniverseObjectUnRegistered?.Invoke(this, new(universeObject));
 | 
						|
 | 
						|
        universeObject.OnFinalized.RemoveListener(delegateOnUniverseObjectFinalize);
 | 
						|
        universeObject.OnExitedUniverse.RemoveListener(delegateOnUniverseObjectExitedUniverse);
 | 
						|
 | 
						|
        for (int i = universeObject.Children.Count - 1; i >= 0; i--)
 | 
						|
            Remove(universeObject.Children[i]);
 | 
						|
 | 
						|
        _universeObjects.Remove(universeObject);
 | 
						|
 | 
						|
        if (!universeObject.ExitUniverse())
 | 
						|
            throw new Exception($"{universeObject.Name} can't exit the universe");
 | 
						|
 | 
						|
        if (!universeObject.Finalize())
 | 
						|
            throw new Exception($"{universeObject.Name} can't be finalized");
 | 
						|
 | 
						|
        OnUniverseObjectUnRegistered?.Invoke(this, new(universeObject));
 | 
						|
    }
 | 
						|
 | 
						|
    protected override void InitializeInternal()
 | 
						|
    {
 | 
						|
        foreach (IUniverseObject universeObject in _universeObjects)
 | 
						|
            universeObject.Initialize();
 | 
						|
    }
 | 
						|
 | 
						|
    protected override void FinalizeInternal()
 | 
						|
    {
 | 
						|
        base.FinalizeInternal();
 | 
						|
        for (int i = _universeObjects.Count - 1; i >= 0; i--)
 | 
						|
            Remove(_universeObjects[i]);
 | 
						|
    }
 | 
						|
 | 
						|
    public void Update(UniverseTime engineTime)
 | 
						|
    {
 | 
						|
        Debug.Assert.AssertInitialized(this);
 | 
						|
 | 
						|
        UnscaledTime = engineTime;
 | 
						|
        Time = new(TimeSpan.FromTicks((long)(Time.TimeSinceStart.Ticks + engineTime.DeltaSpan.Ticks * TimeScale)), TimeSpan.FromTicks((long)(engineTime.DeltaSpan.Ticks * TimeScale)));
 | 
						|
 | 
						|
        IUniverse.UpdateArguments args = new(Time);
 | 
						|
        OnPreUpdate?.Invoke(this, args);
 | 
						|
        OnUpdate?.Invoke(this, args);
 | 
						|
        OnPostUpdate?.Invoke(this, args);
 | 
						|
    }
 | 
						|
 | 
						|
    public void Draw()
 | 
						|
    {
 | 
						|
        Debug.Assert.AssertInitialized(this);
 | 
						|
 | 
						|
        OnPreDraw?.Invoke(this);
 | 
						|
        OnDraw?.Invoke(this);
 | 
						|
        OnPostDraw?.Invoke(this);
 | 
						|
    }
 | 
						|
 | 
						|
    private void OnUniverseObjectFinalize(IInitializable initializable)
 | 
						|
    {
 | 
						|
        if (initializable is IUniverseObject universeObject)
 | 
						|
            Remove(universeObject);
 | 
						|
    }
 | 
						|
 | 
						|
    private void OnUniverseObjectExitedUniverse(IUniverseObject sender, IUniverseObject.ExitedUniverseArguments args)
 | 
						|
    {
 | 
						|
        if (sender is IUniverseObject universeObject)
 | 
						|
            Remove(universeObject);
 | 
						|
    }
 | 
						|
 | 
						|
    public IEnumerator<IUniverseObject> GetEnumerator() => Root.TraverseChildren();
 | 
						|
    IEnumerator IEnumerable.GetEnumerator() => Root.TraverseChildren();
 | 
						|
}
 |