Compare commits
	
		
			42 Commits
		
	
	
		
			tests
			...
			dbd15cbbc2
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| dbd15cbbc2 | |||
| e051f5cfb4 | |||
| e70b7f112f | |||
| f55ba499b6 | |||
| b75f30f864 | |||
| 6f1f30bd53 | |||
| 92a5c276a4 | |||
| 69bc6573d1 | |||
| 28bc022587 | |||
| 25db60e436 | |||
| 7c62440bba | |||
| 4bec7bce6e | |||
| 8d31372c24 | |||
| a2e704916e | |||
| c7d170fad9 | |||
| 9ccf7b754d | |||
| e3d4899112 | |||
| 566c16d09c | |||
| ae9d4f02ef | |||
| e77772cbc2 | |||
| 4c542df401 | |||
| 28ca343b43 | |||
| 651b0614c4 | |||
| f47488c6f1 | |||
| 6d159330a1 | |||
| 8e314f3269 | |||
| f5a7077570 | |||
| 746d29fb7a | |||
| cf68f6ca6f | |||
| a4b83679b1 | |||
| a31b39fd1d | |||
| 0205354202 | |||
| 949dfeb3d9 | |||
| 620ef911fa | |||
| efed24de20 | |||
| 3912706d27 | |||
| d78c42a653 | |||
| b04e0f81cd | |||
| 65dcb0c564 | |||
| 3d183b21cd | |||
| 1644a751bb | |||
| 6631cae7b0 | 
							
								
								
									
										6
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							@@ -1,3 +1,3 @@
 | 
			
		||||
[submodule "Engine.Serializers/YamlDotNet"]
 | 
			
		||||
	path = Engine.Serializers/YamlDotNet
 | 
			
		||||
	url = git@github.com:Syntriax/YamlDotNet.git
 | 
			
		||||
[submodule "Engine.Integration/YamlDotNet"]
 | 
			
		||||
	path = Engine.Integration/YamlDotNet
 | 
			
		||||
	url = https://github.com/Syntriax/YamlDotNet.git
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Indicates the class implementing it has Assignable fields that are necessary for the engine to work properly.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Indicates the object is an <see cref="IAssignable"/> with an assignable <see cref="IBehaviourController"/> field.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Indicates the object is an <see cref="IAssignable"/> with an assignable <see cref="IEntity"/> field.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Indicates the object is an <see cref="IAssignable"/> with an assignable <see cref="IStateEnable"/> field.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Indicates the object is an <see cref="IAssignable"/> with an assignable <see cref="IUniverse"/> field.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Indicates the object is an <see cref="IAssignable"/> with an assignable <see cref="IUniverseObject"/> field.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents an entity which can be active or not.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents a behaviour that any object in the engine that might use to interact with itself or other objects. 
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
public interface IBehaviour2D : IBehaviour
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents a collector for the class type of <typeparamref name="T"/>.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents a controller for managing <see cref="IBehaviour"/>s. Connected to an <see cref="IUniverseObject"/>.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents a 2D camera in the engine.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
public interface ICoroutineYield
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents a basic entity in the engine.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents an entity that can be initialized and finalized. This information is useful for objects we know that are not in use and can be either recycled or dropped for garbage collection.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents an entity with a name.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents an entity with an enable state that can be toggled.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents the transformation properties of an object such as position, scale, and rotation in 2D space.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents a universe responsible for managing <see cref="IUniverseObject"/>s.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents an <see cref="IEntity"/> that can enter and exit a universe within the <see cref="IUniverse"/> system.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,67 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
public class ActiveBehaviourCollectorSorted<T> : ActiveBehaviourCollector<T> where T : class, IBehaviour
 | 
			
		||||
{
 | 
			
		||||
    private readonly Event<IBehaviour, IBehaviour.PriorityChangedArguments>.EventHandler delegateOnPriorityChanged = null!;
 | 
			
		||||
 | 
			
		||||
    private IComparer<T>? _sortBy = null;
 | 
			
		||||
    public IComparer<T>? SortBy
 | 
			
		||||
    {
 | 
			
		||||
        get => _sortBy;
 | 
			
		||||
        set
 | 
			
		||||
        {
 | 
			
		||||
            _sortBy = value;
 | 
			
		||||
 | 
			
		||||
            if (value is not null)
 | 
			
		||||
                activeBehaviours.Sort(value);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void AddBehaviour(T behaviour)
 | 
			
		||||
    {
 | 
			
		||||
        if (SortBy is null)
 | 
			
		||||
        {
 | 
			
		||||
            activeBehaviours.Add(behaviour);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        int insertionIndex = activeBehaviours.BinarySearch(behaviour, SortBy);
 | 
			
		||||
 | 
			
		||||
        if (insertionIndex < 0)
 | 
			
		||||
            insertionIndex = ~insertionIndex;
 | 
			
		||||
 | 
			
		||||
        activeBehaviours.Insert(insertionIndex, behaviour);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void OnBehaviourAdd(IBehaviour behaviour)
 | 
			
		||||
    {
 | 
			
		||||
        behaviour.OnPriorityChanged.AddListener(delegateOnPriorityChanged);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void OnBehaviourRemove(IBehaviour behaviour)
 | 
			
		||||
    {
 | 
			
		||||
        behaviour.OnPriorityChanged.RemoveListener(delegateOnPriorityChanged);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void OnPriorityChanged(IBehaviour sender, IBehaviour.PriorityChangedArguments args)
 | 
			
		||||
    {
 | 
			
		||||
        T behaviour = (T)sender;
 | 
			
		||||
        activeBehaviours.Remove(behaviour);
 | 
			
		||||
        AddBehaviour(behaviour);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ActiveBehaviourCollectorSorted()
 | 
			
		||||
    {
 | 
			
		||||
        delegateOnPriorityChanged = OnPriorityChanged;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ActiveBehaviourCollectorSorted(IUniverse universe, Comparison<T> sortBy) : base(universe)
 | 
			
		||||
    {
 | 
			
		||||
        delegateOnPriorityChanged = OnPriorityChanged;
 | 
			
		||||
 | 
			
		||||
        SortBy = Comparer<T>.Create(sortBy);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
public abstract class BaseEntity : IEntity
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
public abstract class Behaviour : BehaviourBase
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
public abstract class Behaviour2D : Behaviour, IBehaviour2D
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
[System.Diagnostics.DebuggerDisplay("{GetType().Name, nq}, Priority: {Priority}, Initialized: {Initialized}")]
 | 
			
		||||
public abstract class BehaviourBase : BaseEntity, IBehaviour
 | 
			
		||||
 
 | 
			
		||||
@@ -1,67 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
public class BehaviourCollectorSorted<T> : BehaviourCollector<T> where T : class
 | 
			
		||||
{
 | 
			
		||||
    private readonly Event<IBehaviour, IBehaviour.PriorityChangedArguments>.EventHandler delegateOnPriorityChanged = null!;
 | 
			
		||||
 | 
			
		||||
    private IComparer<T>? _sortBy = null;
 | 
			
		||||
    public IComparer<T>? SortBy
 | 
			
		||||
    {
 | 
			
		||||
        get => _sortBy;
 | 
			
		||||
        set
 | 
			
		||||
        {
 | 
			
		||||
            _sortBy = value;
 | 
			
		||||
 | 
			
		||||
            if (value is not null)
 | 
			
		||||
                behaviours.Sort(value);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void AddBehaviour(T behaviour)
 | 
			
		||||
    {
 | 
			
		||||
        if (SortBy is null)
 | 
			
		||||
        {
 | 
			
		||||
            behaviours.Add(behaviour);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        int insertionIndex = behaviours.BinarySearch(behaviour, SortBy);
 | 
			
		||||
 | 
			
		||||
        if (insertionIndex < 0)
 | 
			
		||||
            insertionIndex = ~insertionIndex;
 | 
			
		||||
 | 
			
		||||
        behaviours.Insert(insertionIndex, behaviour);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void OnBehaviourAdd(IBehaviour behaviour)
 | 
			
		||||
    {
 | 
			
		||||
        behaviour.OnPriorityChanged.AddListener(delegateOnPriorityChanged);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void OnBehaviourRemove(IBehaviour behaviour)
 | 
			
		||||
    {
 | 
			
		||||
        behaviour.OnPriorityChanged.RemoveListener(delegateOnPriorityChanged);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void OnPriorityChanged(IBehaviour sender, IBehaviour.PriorityChangedArguments args)
 | 
			
		||||
    {
 | 
			
		||||
        T behaviour = (T)sender;
 | 
			
		||||
        behaviours.Remove(behaviour);
 | 
			
		||||
        AddBehaviour(behaviour);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public BehaviourCollectorSorted()
 | 
			
		||||
    {
 | 
			
		||||
        delegateOnPriorityChanged = OnPriorityChanged;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public BehaviourCollectorSorted(IUniverse universe, Comparison<T> sortBy) : base(universe)
 | 
			
		||||
    {
 | 
			
		||||
        delegateOnPriorityChanged = OnPriorityChanged;
 | 
			
		||||
 | 
			
		||||
        SortBy = Comparer<T>.Create(sortBy);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
[System.Diagnostics.DebuggerDisplay("Behaviour Count: {behaviours.Count}")]
 | 
			
		||||
public class BehaviourController : BaseEntity, IBehaviourController
 | 
			
		||||
@@ -10,7 +10,7 @@ public class BehaviourController : BaseEntity, IBehaviourController
 | 
			
		||||
    public Event<IBehaviourController, IBehaviourController.BehaviourRemovedArguments> OnBehaviourRemoved { get; } = new();
 | 
			
		||||
    public Event<IHasUniverseObject> OnUniverseObjectAssigned { get; } = new();
 | 
			
		||||
 | 
			
		||||
    private readonly List<IBehaviour> behaviours = new(Constants.BEHAVIOURS_SIZE_INITIAL);
 | 
			
		||||
    private readonly FastList<IBehaviour> behaviours = new(Constants.BEHAVIOURS_SIZE_INITIAL);
 | 
			
		||||
 | 
			
		||||
    private IUniverseObject _universeObject = null!;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16
									
								
								Engine.Core/Collectors/ActiveBehaviourCollector.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								Engine.Core/Collectors/ActiveBehaviourCollector.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
public class ActiveBehaviourCollector<T> : ActiveBehaviourCollectorBase<T> where T : class, IBehaviour
 | 
			
		||||
{
 | 
			
		||||
    protected readonly FastList<T> activeBehaviours = new(32);
 | 
			
		||||
    public override T this[Index index] => activeBehaviours[index];
 | 
			
		||||
    public override int Count => activeBehaviours.Count;
 | 
			
		||||
 | 
			
		||||
    public ActiveBehaviourCollector() { }
 | 
			
		||||
    public ActiveBehaviourCollector(IUniverse universe) : base(universe) { }
 | 
			
		||||
 | 
			
		||||
    protected override void AddBehaviour(T behaviour) => activeBehaviours.Add(behaviour);
 | 
			
		||||
    protected override bool RemoveBehaviour(T tBehaviour) => activeBehaviours.Remove(tBehaviour);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,14 +1,12 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
public class ActiveBehaviourCollector<T> : IBehaviourCollector<T> where T : class, IBehaviour
 | 
			
		||||
public abstract class ActiveBehaviourCollectorBase<T> : IBehaviourCollector<T> where T : class, IBehaviour
 | 
			
		||||
{
 | 
			
		||||
    public Event<IBehaviourCollector<T>, IBehaviourCollector<T>.BehaviourCollectedArguments> OnCollected { get; } = new();
 | 
			
		||||
    public Event<IBehaviourCollector<T>, IBehaviourCollector<T>.BehaviourRemovedArguments> OnRemoved { get; } = new();
 | 
			
		||||
    public Event<IHasUniverse> OnUniverseAssigned { get; } = new();
 | 
			
		||||
    public Event<IAssignable>? OnUnassigned { get; } = new();
 | 
			
		||||
    protected readonly Dictionary<IActive, T> monitoringActiveToBehaviour = new(32);
 | 
			
		||||
    protected readonly FastList<T> monitoringBehaviours = new(32);
 | 
			
		||||
 | 
			
		||||
    private readonly Event<IBehaviourController, IBehaviourController.BehaviourAddedArguments>.EventHandler delegateOnBehaviourAdded = null!;
 | 
			
		||||
    private readonly Event<IBehaviourController, IBehaviourController.BehaviourRemovedArguments>.EventHandler delegateOnBehaviourRemoved = null!;
 | 
			
		||||
@@ -16,80 +14,16 @@ public class ActiveBehaviourCollector<T> : IBehaviourCollector<T> where T : clas
 | 
			
		||||
    private readonly Event<IUniverse, IUniverse.UniverseObjectRegisteredArguments>.EventHandler delegateOnUniverseObjectRegistered = null!;
 | 
			
		||||
    private readonly Event<IUniverse, IUniverse.UniverseObjectUnRegisteredArguments>.EventHandler delegateOnUniverseObjectUnregistered = null!;
 | 
			
		||||
 | 
			
		||||
    private readonly List<T> monitoringBehaviours = new(32);
 | 
			
		||||
    protected readonly List<T> activeBehaviours = new(32);
 | 
			
		||||
    protected readonly Dictionary<IActive, T> monitoringActiveToBehaviour = new(32);
 | 
			
		||||
    public Event<IBehaviourCollector<T>, IBehaviourCollector<T>.BehaviourCollectedArguments> OnCollected { get; } = new();
 | 
			
		||||
    public Event<IBehaviourCollector<T>, IBehaviourCollector<T>.BehaviourRemovedArguments> OnRemoved { get; } = new();
 | 
			
		||||
    public Event<IHasUniverse> OnUniverseAssigned { get; } = new();
 | 
			
		||||
    public Event<IAssignable>? OnUnassigned { get; } = new();
 | 
			
		||||
 | 
			
		||||
    public abstract int Count { get; }
 | 
			
		||||
 | 
			
		||||
    public abstract T this[Index index] { get; }
 | 
			
		||||
    public IUniverse Universe { get; private set; } = null!;
 | 
			
		||||
 | 
			
		||||
    private void OnUniverseObjectRegistered(IUniverse manager, IUniverse.UniverseObjectRegisteredArguments args)
 | 
			
		||||
    {
 | 
			
		||||
        IUniverseObject universeObject = args.UniverseObjectRegistered;
 | 
			
		||||
 | 
			
		||||
        universeObject.BehaviourController.OnBehaviourAdded.AddListener(delegateOnBehaviourAdded);
 | 
			
		||||
        universeObject.BehaviourController.OnBehaviourRemoved.AddListener(delegateOnBehaviourRemoved);
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < universeObject.BehaviourController.Count; i++)
 | 
			
		||||
            OnBehaviourAdded(universeObject.BehaviourController, new(universeObject.BehaviourController[i]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void OnUniverseObjectUnregistered(IUniverse manager, IUniverse.UniverseObjectUnRegisteredArguments args)
 | 
			
		||||
    {
 | 
			
		||||
        IUniverseObject universeObject = args.UniverseObjectUnregistered;
 | 
			
		||||
 | 
			
		||||
        universeObject.BehaviourController.OnBehaviourAdded.RemoveListener(delegateOnBehaviourAdded);
 | 
			
		||||
        universeObject.BehaviourController.OnBehaviourRemoved.RemoveListener(delegateOnBehaviourRemoved);
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < universeObject.BehaviourController.Count; i++)
 | 
			
		||||
            OnBehaviourRemoved(universeObject.BehaviourController, new(universeObject.BehaviourController[i]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected virtual void OnBehaviourAdd(IBehaviour behaviour) { }
 | 
			
		||||
    private void OnBehaviourAdded(IBehaviourController controller, IBehaviourController.BehaviourAddedArguments args)
 | 
			
		||||
    {
 | 
			
		||||
        if (args.BehaviourAdded is not T tBehaviour)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        monitoringBehaviours.Add(tBehaviour);
 | 
			
		||||
        monitoringActiveToBehaviour.Add(tBehaviour, tBehaviour);
 | 
			
		||||
        tBehaviour.OnActiveChanged.AddListener(delegateOnBehaviourStateChanged);
 | 
			
		||||
        OnBehaviourStateChanged(tBehaviour, new(!tBehaviour.IsActive));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected virtual void AddBehaviour(T behaviour) => activeBehaviours.Add(behaviour);
 | 
			
		||||
    private void OnBehaviourStateChanged(IActive sender, IActive.ActiveChangedArguments args)
 | 
			
		||||
    {
 | 
			
		||||
        T behaviour = monitoringActiveToBehaviour[sender];
 | 
			
		||||
        if (sender.IsActive)
 | 
			
		||||
        {
 | 
			
		||||
            AddBehaviour(behaviour);
 | 
			
		||||
            OnBehaviourAdd(behaviour);
 | 
			
		||||
            OnCollected?.Invoke(this, new(behaviour));
 | 
			
		||||
        }
 | 
			
		||||
        else if (activeBehaviours.Remove(behaviour))
 | 
			
		||||
        {
 | 
			
		||||
            OnBehaviourRemove(behaviour);
 | 
			
		||||
            OnRemoved?.Invoke(this, new(behaviour));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected virtual void OnBehaviourRemove(IBehaviour behaviour) { }
 | 
			
		||||
    private void OnBehaviourRemoved(IBehaviourController controller, IBehaviourController.BehaviourRemovedArguments args)
 | 
			
		||||
    {
 | 
			
		||||
        if (args.BehaviourRemoved is not T tBehaviour)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (!monitoringBehaviours.Remove(tBehaviour) || !monitoringActiveToBehaviour.Remove(tBehaviour))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        tBehaviour.OnActiveChanged.RemoveListener(delegateOnBehaviourStateChanged);
 | 
			
		||||
        if (activeBehaviours.Remove(tBehaviour))
 | 
			
		||||
        {
 | 
			
		||||
            OnBehaviourRemove(tBehaviour);
 | 
			
		||||
            OnRemoved?.Invoke(this, new(tBehaviour));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool Assign(IUniverse universe)
 | 
			
		||||
    {
 | 
			
		||||
        if (Universe is not null)
 | 
			
		||||
@@ -123,10 +57,75 @@ public class ActiveBehaviourCollector<T> : IBehaviourCollector<T> where T : clas
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int Count => activeBehaviours.Count;
 | 
			
		||||
    public T this[Index index] => activeBehaviours[index];
 | 
			
		||||
    protected abstract void AddBehaviour(T behaviour);
 | 
			
		||||
    protected virtual void OnBehaviourAdd(IBehaviour behaviour) { }
 | 
			
		||||
    private void OnBehaviourAdded(IBehaviourController controller, IBehaviourController.BehaviourAddedArguments args)
 | 
			
		||||
    {
 | 
			
		||||
        if (args.BehaviourAdded is not T tBehaviour)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
    public ActiveBehaviourCollector()
 | 
			
		||||
        monitoringBehaviours.Add(tBehaviour);
 | 
			
		||||
        monitoringActiveToBehaviour.Add(tBehaviour, tBehaviour);
 | 
			
		||||
        tBehaviour.OnActiveChanged.AddListener(delegateOnBehaviourStateChanged);
 | 
			
		||||
        OnBehaviourStateChanged(tBehaviour, new(!tBehaviour.IsActive));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected abstract bool RemoveBehaviour(T behaviour);
 | 
			
		||||
    protected virtual void OnBehaviourRemove(IBehaviour behaviour) { }
 | 
			
		||||
    private void OnBehaviourRemoved(IBehaviourController controller, IBehaviourController.BehaviourRemovedArguments args)
 | 
			
		||||
    {
 | 
			
		||||
        if (args.BehaviourRemoved is not T tBehaviour)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (!monitoringBehaviours.Remove(tBehaviour) || !monitoringActiveToBehaviour.Remove(tBehaviour))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        tBehaviour.OnActiveChanged.RemoveListener(delegateOnBehaviourStateChanged);
 | 
			
		||||
        if (!RemoveBehaviour(tBehaviour))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        OnBehaviourRemove(tBehaviour);
 | 
			
		||||
        OnRemoved?.Invoke(this, new(tBehaviour));
 | 
			
		||||
    }
 | 
			
		||||
    private void OnBehaviourStateChanged(IActive sender, IActive.ActiveChangedArguments args)
 | 
			
		||||
    {
 | 
			
		||||
        T behaviour = monitoringActiveToBehaviour[sender];
 | 
			
		||||
        if (sender.IsActive)
 | 
			
		||||
        {
 | 
			
		||||
            AddBehaviour(behaviour);
 | 
			
		||||
            OnBehaviourAdd(behaviour);
 | 
			
		||||
            OnCollected?.Invoke(this, new(behaviour));
 | 
			
		||||
        }
 | 
			
		||||
        else if (RemoveBehaviour(behaviour))
 | 
			
		||||
        {
 | 
			
		||||
            OnBehaviourRemove(behaviour);
 | 
			
		||||
            OnRemoved?.Invoke(this, new(behaviour));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void OnUniverseObjectRegistered(IUniverse manager, IUniverse.UniverseObjectRegisteredArguments args)
 | 
			
		||||
    {
 | 
			
		||||
        IUniverseObject universeObject = args.UniverseObjectRegistered;
 | 
			
		||||
 | 
			
		||||
        universeObject.BehaviourController.OnBehaviourAdded.AddListener(delegateOnBehaviourAdded);
 | 
			
		||||
        universeObject.BehaviourController.OnBehaviourRemoved.AddListener(delegateOnBehaviourRemoved);
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < universeObject.BehaviourController.Count; i++)
 | 
			
		||||
            OnBehaviourAdded(universeObject.BehaviourController, new(universeObject.BehaviourController[i]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void OnUniverseObjectUnregistered(IUniverse manager, IUniverse.UniverseObjectUnRegisteredArguments args)
 | 
			
		||||
    {
 | 
			
		||||
        IUniverseObject universeObject = args.UniverseObjectUnregistered;
 | 
			
		||||
 | 
			
		||||
        universeObject.BehaviourController.OnBehaviourAdded.RemoveListener(delegateOnBehaviourAdded);
 | 
			
		||||
        universeObject.BehaviourController.OnBehaviourRemoved.RemoveListener(delegateOnBehaviourRemoved);
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < universeObject.BehaviourController.Count; i++)
 | 
			
		||||
            OnBehaviourRemoved(universeObject.BehaviourController, new(universeObject.BehaviourController[i]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ActiveBehaviourCollectorBase()
 | 
			
		||||
    {
 | 
			
		||||
        delegateOnBehaviourAdded = OnBehaviourAdded;
 | 
			
		||||
        delegateOnBehaviourRemoved = OnBehaviourRemoved;
 | 
			
		||||
@@ -135,7 +134,7 @@ public class ActiveBehaviourCollector<T> : IBehaviourCollector<T> where T : clas
 | 
			
		||||
        delegateOnUniverseObjectUnregistered = OnUniverseObjectUnregistered;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ActiveBehaviourCollector(IUniverse universe)
 | 
			
		||||
    public ActiveBehaviourCollectorBase(IUniverse universe)
 | 
			
		||||
    {
 | 
			
		||||
        delegateOnBehaviourAdded = OnBehaviourAdded;
 | 
			
		||||
        delegateOnBehaviourRemoved = OnBehaviourRemoved;
 | 
			
		||||
							
								
								
									
										104
									
								
								Engine.Core/Collectors/ActiveBehaviourCollectorOrdered.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								Engine.Core/Collectors/ActiveBehaviourCollectorOrdered.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,104 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
public class ActiveBehaviourCollectorOrdered<TIndex, TItem> : ActiveBehaviourCollector<TItem> where TItem : class, IBehaviour where TIndex : IComparable
 | 
			
		||||
{
 | 
			
		||||
    private readonly Event<IBehaviour, IBehaviour.PriorityChangedArguments>.EventHandler delegateOnPriorityChanged = null!;
 | 
			
		||||
 | 
			
		||||
    private readonly SortedDictionary<TIndex, FastList<TItem>> behaviours = null!;
 | 
			
		||||
 | 
			
		||||
    private readonly Func<TItem, TIndex> getIndexFunc = null!;
 | 
			
		||||
    private readonly IComparer<TIndex> sortBy = null!;
 | 
			
		||||
 | 
			
		||||
    private int count = 0;
 | 
			
		||||
    public override int Count => count;
 | 
			
		||||
 | 
			
		||||
    public override TItem this[Index index]
 | 
			
		||||
    {
 | 
			
		||||
        get
 | 
			
		||||
        {
 | 
			
		||||
            int actualIndex = index.IsFromEnd
 | 
			
		||||
                ? count - index.Value
 | 
			
		||||
                : index.Value;
 | 
			
		||||
 | 
			
		||||
            if (actualIndex < 0 || actualIndex >= count)
 | 
			
		||||
                throw new IndexOutOfRangeException();
 | 
			
		||||
 | 
			
		||||
            int leftIndex = actualIndex;
 | 
			
		||||
            foreach ((TIndex i, FastList<TItem> list) in behaviours)
 | 
			
		||||
            {
 | 
			
		||||
                if (leftIndex < list.Count)
 | 
			
		||||
                    return list[leftIndex];
 | 
			
		||||
                leftIndex -= list.Count;
 | 
			
		||||
            }
 | 
			
		||||
            throw new IndexOutOfRangeException();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override bool RemoveBehaviour(TItem tBehaviour)
 | 
			
		||||
    {
 | 
			
		||||
        TIndex index = getIndexFunc(tBehaviour);
 | 
			
		||||
        if (!behaviours.TryGetValue(index, out FastList<TItem>? list))
 | 
			
		||||
            throw new Exceptions.NotFoundException($"Index of '{index}' is not found in the collector");
 | 
			
		||||
 | 
			
		||||
        if (!list.Remove(tBehaviour))
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        count--;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void AddBehaviour(TItem behaviour)
 | 
			
		||||
    {
 | 
			
		||||
        TIndex key = getIndexFunc(behaviour);
 | 
			
		||||
        if (!behaviours.TryGetValue(key, out FastList<TItem>? list))
 | 
			
		||||
            behaviours[key] = list = [];
 | 
			
		||||
 | 
			
		||||
        count++;
 | 
			
		||||
        list.Add(behaviour);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void OnBehaviourAdd(IBehaviour behaviour) => behaviour.OnPriorityChanged.AddListener(delegateOnPriorityChanged);
 | 
			
		||||
    protected override void OnBehaviourRemove(IBehaviour behaviour) => behaviour.OnPriorityChanged.RemoveListener(delegateOnPriorityChanged);
 | 
			
		||||
 | 
			
		||||
    private void OnPriorityChanged(IBehaviour sender, IBehaviour.PriorityChangedArguments args)
 | 
			
		||||
    {
 | 
			
		||||
        TItem behaviour = (TItem)sender;
 | 
			
		||||
        RemoveBehaviour(behaviour);
 | 
			
		||||
        AddBehaviour(behaviour);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ActiveBehaviourCollectorOrdered(Func<TItem, TIndex> getIndexFunc, Comparison<TIndex> sortBy)
 | 
			
		||||
    {
 | 
			
		||||
        delegateOnPriorityChanged = OnPriorityChanged;
 | 
			
		||||
        this.getIndexFunc = getIndexFunc;
 | 
			
		||||
        this.sortBy = Comparer<TIndex>.Create(sortBy);
 | 
			
		||||
        behaviours = new(this.sortBy);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ActiveBehaviourCollectorOrdered(IUniverse universe, Func<TItem, TIndex> getIndexFunc, Comparison<TIndex> sortBy) : base(universe)
 | 
			
		||||
    {
 | 
			
		||||
        delegateOnPriorityChanged = OnPriorityChanged;
 | 
			
		||||
        this.getIndexFunc = getIndexFunc;
 | 
			
		||||
        this.sortBy = Comparer<TIndex>.Create(sortBy);
 | 
			
		||||
        behaviours = new(this.sortBy);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ActiveBehaviourCollectorOrdered(Func<TItem, TIndex> getIndexFunc, IComparer<TIndex> sortBy)
 | 
			
		||||
    {
 | 
			
		||||
        this.getIndexFunc = getIndexFunc;
 | 
			
		||||
        delegateOnPriorityChanged = OnPriorityChanged;
 | 
			
		||||
        this.sortBy = sortBy;
 | 
			
		||||
        behaviours = new(sortBy);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ActiveBehaviourCollectorOrdered(IUniverse universe, Func<TItem, TIndex> getIndexFunc, IComparer<TIndex> sortBy) : base(universe)
 | 
			
		||||
    {
 | 
			
		||||
        delegateOnPriorityChanged = OnPriorityChanged;
 | 
			
		||||
        this.getIndexFunc = getIndexFunc;
 | 
			
		||||
        this.sortBy = sortBy;
 | 
			
		||||
        behaviours = new(sortBy);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										17
									
								
								Engine.Core/Collectors/BehaviourCollector.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								Engine.Core/Collectors/BehaviourCollector.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
public class BehaviourCollector<T> : BehaviourCollectorBase<T> where T : class
 | 
			
		||||
{
 | 
			
		||||
    protected readonly FastList<T> behaviours = new(32);
 | 
			
		||||
 | 
			
		||||
    public override T this[Index index] => behaviours[index];
 | 
			
		||||
    public override int Count => behaviours.Count;
 | 
			
		||||
 | 
			
		||||
    protected override void AddBehaviour(T behaviour) => behaviours.Add(behaviour);
 | 
			
		||||
    protected override bool RemoveBehaviour(T tBehaviour) => behaviours.Remove(tBehaviour);
 | 
			
		||||
 | 
			
		||||
    public BehaviourCollector() { }
 | 
			
		||||
    public BehaviourCollector(IUniverse universe) : base(universe) { }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,72 +1,25 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
public class BehaviourCollector<T> : IBehaviourCollector<T> where T : class
 | 
			
		||||
public abstract class BehaviourCollectorBase<T> : IBehaviourCollector<T> where T : class
 | 
			
		||||
{
 | 
			
		||||
    public Event<IBehaviourCollector<T>, IBehaviourCollector<T>.BehaviourCollectedArguments> OnCollected { get; } = new();
 | 
			
		||||
    public Event<IBehaviourCollector<T>, IBehaviourCollector<T>.BehaviourRemovedArguments> OnRemoved { get; } = new();
 | 
			
		||||
    public Event<IHasUniverse> OnUniverseAssigned { get; } = new();
 | 
			
		||||
    public Event<IAssignable>? OnUnassigned { get; } = new();
 | 
			
		||||
 | 
			
		||||
    private readonly Event<IBehaviourController, IBehaviourController.BehaviourAddedArguments>.EventHandler delegateOnBehaviourAdded = null!;
 | 
			
		||||
    private readonly Event<IBehaviourController, IBehaviourController.BehaviourRemovedArguments>.EventHandler delegateOnBehaviourRemoved = null!;
 | 
			
		||||
    private readonly Event<IUniverse, IUniverse.UniverseObjectRegisteredArguments>.EventHandler delegateOnUniverseObjectRegistered = null!;
 | 
			
		||||
    private readonly Event<IUniverse, IUniverse.UniverseObjectUnRegisteredArguments>.EventHandler delegateOnUniverseObjectUnregistered = null!;
 | 
			
		||||
 | 
			
		||||
    protected readonly List<T> behaviours = new(32);
 | 
			
		||||
    public Event<IBehaviourCollector<T>, IBehaviourCollector<T>.BehaviourCollectedArguments> OnCollected { get; } = new();
 | 
			
		||||
    public Event<IBehaviourCollector<T>, IBehaviourCollector<T>.BehaviourRemovedArguments> OnRemoved { get; } = new();
 | 
			
		||||
    public Event<IHasUniverse> OnUniverseAssigned { get; } = new();
 | 
			
		||||
    public Event<IAssignable>? OnUnassigned { get; } = new();
 | 
			
		||||
 | 
			
		||||
    public IUniverse Universe { get; private set; } = null!;
 | 
			
		||||
 | 
			
		||||
    private void OnUniverseObjectRegistered(IUniverse manager, IUniverse.UniverseObjectRegisteredArguments args)
 | 
			
		||||
    {
 | 
			
		||||
        IUniverseObject universeObject = args.UniverseObjectRegistered;
 | 
			
		||||
    public abstract int Count { get; }
 | 
			
		||||
 | 
			
		||||
        universeObject.BehaviourController.OnBehaviourAdded.AddListener(delegateOnBehaviourAdded);
 | 
			
		||||
        universeObject.BehaviourController.OnBehaviourRemoved.AddListener(delegateOnBehaviourRemoved);
 | 
			
		||||
    public abstract T this[Index index] { get; }
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < universeObject.BehaviourController.Count; i++)
 | 
			
		||||
            OnBehaviourAdded(universeObject.BehaviourController, new(universeObject.BehaviourController[i]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void OnUniverseObjectUnregistered(IUniverse manager, IUniverse.UniverseObjectUnRegisteredArguments args)
 | 
			
		||||
    {
 | 
			
		||||
        IUniverseObject universeObject = args.UniverseObjectUnregistered;
 | 
			
		||||
 | 
			
		||||
        universeObject.BehaviourController.OnBehaviourAdded.RemoveListener(delegateOnBehaviourAdded);
 | 
			
		||||
        universeObject.BehaviourController.OnBehaviourRemoved.RemoveListener(delegateOnBehaviourRemoved);
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < universeObject.BehaviourController.Count; i++)
 | 
			
		||||
            OnBehaviourRemoved(universeObject.BehaviourController, new(universeObject.BehaviourController[i]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected virtual void AddBehaviour(T behaviour) => behaviours.Add(behaviour);
 | 
			
		||||
    protected virtual void OnBehaviourAdd(IBehaviour behaviour) { }
 | 
			
		||||
    private void OnBehaviourAdded(IBehaviourController controller, IBehaviourController.BehaviourAddedArguments args)
 | 
			
		||||
    {
 | 
			
		||||
        if (args.BehaviourAdded is not T tBehaviour)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        AddBehaviour(tBehaviour);
 | 
			
		||||
        OnBehaviourAdd(args.BehaviourAdded);
 | 
			
		||||
        OnCollected?.Invoke(this, new(tBehaviour));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected virtual void OnBehaviourRemove(IBehaviour behaviour) { }
 | 
			
		||||
    private void OnBehaviourRemoved(IBehaviourController controller, IBehaviourController.BehaviourRemovedArguments args)
 | 
			
		||||
    {
 | 
			
		||||
        if (args.BehaviourRemoved is not T tBehaviour)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (!behaviours.Remove(tBehaviour))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        OnBehaviourRemove(args.BehaviourRemoved);
 | 
			
		||||
        OnRemoved?.Invoke(this, new(tBehaviour));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected virtual void OnAssign(IUniverse universe) { }
 | 
			
		||||
    public bool Assign(IUniverse universe)
 | 
			
		||||
    {
 | 
			
		||||
        if (Universe is not null)
 | 
			
		||||
@@ -101,10 +54,57 @@ public class BehaviourCollector<T> : IBehaviourCollector<T> where T : class
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int Count => behaviours.Count;
 | 
			
		||||
    public T this[Index index] => behaviours[index];
 | 
			
		||||
    protected virtual void OnAssign(IUniverse universe) { }
 | 
			
		||||
 | 
			
		||||
    public BehaviourCollector()
 | 
			
		||||
    protected abstract void AddBehaviour(T behaviour);
 | 
			
		||||
    protected virtual void OnBehaviourAdd(IBehaviour behaviour) { }
 | 
			
		||||
    private void OnBehaviourAdded(IBehaviourController controller, IBehaviourController.BehaviourAddedArguments args)
 | 
			
		||||
    {
 | 
			
		||||
        if (args.BehaviourAdded is not T tBehaviour)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        AddBehaviour(tBehaviour);
 | 
			
		||||
        OnBehaviourAdd(args.BehaviourAdded);
 | 
			
		||||
        OnCollected?.Invoke(this, new(tBehaviour));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected abstract bool RemoveBehaviour(T tBehaviour);
 | 
			
		||||
    protected virtual void OnBehaviourRemove(IBehaviour behaviour) { }
 | 
			
		||||
    private void OnBehaviourRemoved(IBehaviourController controller, IBehaviourController.BehaviourRemovedArguments args)
 | 
			
		||||
    {
 | 
			
		||||
        if (args.BehaviourRemoved is not T tBehaviour)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (!RemoveBehaviour(tBehaviour))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        OnBehaviourRemove(args.BehaviourRemoved);
 | 
			
		||||
        OnRemoved?.Invoke(this, new(tBehaviour));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void OnUniverseObjectRegistered(IUniverse manager, IUniverse.UniverseObjectRegisteredArguments args)
 | 
			
		||||
    {
 | 
			
		||||
        IUniverseObject universeObject = args.UniverseObjectRegistered;
 | 
			
		||||
 | 
			
		||||
        universeObject.BehaviourController.OnBehaviourAdded.AddListener(delegateOnBehaviourAdded);
 | 
			
		||||
        universeObject.BehaviourController.OnBehaviourRemoved.AddListener(delegateOnBehaviourRemoved);
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < universeObject.BehaviourController.Count; i++)
 | 
			
		||||
            OnBehaviourAdded(universeObject.BehaviourController, new(universeObject.BehaviourController[i]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void OnUniverseObjectUnregistered(IUniverse manager, IUniverse.UniverseObjectUnRegisteredArguments args)
 | 
			
		||||
    {
 | 
			
		||||
        IUniverseObject universeObject = args.UniverseObjectUnregistered;
 | 
			
		||||
 | 
			
		||||
        universeObject.BehaviourController.OnBehaviourAdded.RemoveListener(delegateOnBehaviourAdded);
 | 
			
		||||
        universeObject.BehaviourController.OnBehaviourRemoved.RemoveListener(delegateOnBehaviourRemoved);
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < universeObject.BehaviourController.Count; i++)
 | 
			
		||||
            OnBehaviourRemoved(universeObject.BehaviourController, new(universeObject.BehaviourController[i]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public BehaviourCollectorBase()
 | 
			
		||||
    {
 | 
			
		||||
        delegateOnBehaviourAdded = OnBehaviourAdded;
 | 
			
		||||
        delegateOnBehaviourRemoved = OnBehaviourRemoved;
 | 
			
		||||
@@ -112,7 +112,7 @@ public class BehaviourCollector<T> : IBehaviourCollector<T> where T : class
 | 
			
		||||
        delegateOnUniverseObjectUnregistered = OnUniverseObjectUnregistered;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public BehaviourCollector(IUniverse universe)
 | 
			
		||||
    public BehaviourCollectorBase(IUniverse universe)
 | 
			
		||||
    {
 | 
			
		||||
        delegateOnBehaviourAdded = OnBehaviourAdded;
 | 
			
		||||
        delegateOnBehaviourRemoved = OnBehaviourRemoved;
 | 
			
		||||
							
								
								
									
										104
									
								
								Engine.Core/Collectors/BehaviourCollectorOrdered.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								Engine.Core/Collectors/BehaviourCollectorOrdered.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,104 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
public class BehaviourCollectorOrdered<TIndex, TItem> : BehaviourCollectorBase<TItem> where TItem : class where TIndex : IComparable
 | 
			
		||||
{
 | 
			
		||||
    private readonly Event<IBehaviour, IBehaviour.PriorityChangedArguments>.EventHandler delegateOnPriorityChanged = null!;
 | 
			
		||||
 | 
			
		||||
    private readonly SortedDictionary<TIndex, FastList<TItem>> behaviours = null!;
 | 
			
		||||
 | 
			
		||||
    private readonly Func<TItem, TIndex> getIndexFunc = null!;
 | 
			
		||||
    private readonly IComparer<TIndex> sortBy = null!;
 | 
			
		||||
 | 
			
		||||
    private int count = 0;
 | 
			
		||||
    public override int Count => count;
 | 
			
		||||
 | 
			
		||||
    public override TItem this[Index index]
 | 
			
		||||
    {
 | 
			
		||||
        get
 | 
			
		||||
        {
 | 
			
		||||
            int actualIndex = index.IsFromEnd
 | 
			
		||||
                ? count - index.Value
 | 
			
		||||
                : index.Value;
 | 
			
		||||
 | 
			
		||||
            if (actualIndex < 0 || actualIndex >= count)
 | 
			
		||||
                throw new IndexOutOfRangeException();
 | 
			
		||||
 | 
			
		||||
            int leftIndex = actualIndex;
 | 
			
		||||
            foreach ((TIndex i, FastList<TItem> list) in behaviours)
 | 
			
		||||
            {
 | 
			
		||||
                if (leftIndex < list.Count)
 | 
			
		||||
                    return list[leftIndex];
 | 
			
		||||
                leftIndex -= list.Count;
 | 
			
		||||
            }
 | 
			
		||||
            throw new IndexOutOfRangeException();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override bool RemoveBehaviour(TItem tBehaviour)
 | 
			
		||||
    {
 | 
			
		||||
        TIndex index = getIndexFunc(tBehaviour);
 | 
			
		||||
        if (!behaviours.TryGetValue(index, out FastList<TItem>? list))
 | 
			
		||||
            throw new Exceptions.NotFoundException($"Index of '{index}' is not found in the collector");
 | 
			
		||||
 | 
			
		||||
        if (!list.Remove(tBehaviour))
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        count--;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void AddBehaviour(TItem behaviour)
 | 
			
		||||
    {
 | 
			
		||||
        TIndex key = getIndexFunc(behaviour);
 | 
			
		||||
        if (!behaviours.TryGetValue(key, out FastList<TItem>? list))
 | 
			
		||||
            behaviours[key] = list = [];
 | 
			
		||||
 | 
			
		||||
        count++;
 | 
			
		||||
        list.Add(behaviour);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void OnBehaviourAdd(IBehaviour behaviour) => behaviour.OnPriorityChanged.AddListener(delegateOnPriorityChanged);
 | 
			
		||||
    protected override void OnBehaviourRemove(IBehaviour behaviour) => behaviour.OnPriorityChanged.RemoveListener(delegateOnPriorityChanged);
 | 
			
		||||
 | 
			
		||||
    private void OnPriorityChanged(IBehaviour sender, IBehaviour.PriorityChangedArguments args)
 | 
			
		||||
    {
 | 
			
		||||
        TItem behaviour = (TItem)sender;
 | 
			
		||||
        RemoveBehaviour(behaviour);
 | 
			
		||||
        AddBehaviour(behaviour);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public BehaviourCollectorOrdered(Func<TItem, TIndex> getIndexFunc, Comparison<TIndex> sortBy)
 | 
			
		||||
    {
 | 
			
		||||
        delegateOnPriorityChanged = OnPriorityChanged;
 | 
			
		||||
        this.getIndexFunc = getIndexFunc;
 | 
			
		||||
        this.sortBy = Comparer<TIndex>.Create(sortBy);
 | 
			
		||||
        behaviours = new(this.sortBy);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public BehaviourCollectorOrdered(IUniverse universe, Func<TItem, TIndex> getIndexFunc, Comparison<TIndex> sortBy) : base(universe)
 | 
			
		||||
    {
 | 
			
		||||
        delegateOnPriorityChanged = OnPriorityChanged;
 | 
			
		||||
        this.getIndexFunc = getIndexFunc;
 | 
			
		||||
        this.sortBy = Comparer<TIndex>.Create(sortBy);
 | 
			
		||||
        behaviours = new(this.sortBy);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public BehaviourCollectorOrdered(Func<TItem, TIndex> getIndexFunc, IComparer<TIndex> sortBy)
 | 
			
		||||
    {
 | 
			
		||||
        this.getIndexFunc = getIndexFunc;
 | 
			
		||||
        delegateOnPriorityChanged = OnPriorityChanged;
 | 
			
		||||
        this.sortBy = sortBy;
 | 
			
		||||
        behaviours = new(sortBy);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public BehaviourCollectorOrdered(IUniverse universe, Func<TItem, TIndex> getIndexFunc, IComparer<TIndex> sortBy) : base(universe)
 | 
			
		||||
    {
 | 
			
		||||
        delegateOnPriorityChanged = OnPriorityChanged;
 | 
			
		||||
        this.getIndexFunc = getIndexFunc;
 | 
			
		||||
        this.sortBy = sortBy;
 | 
			
		||||
        behaviours = new(sortBy);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
using System.Runtime.CompilerServices;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Debug;
 | 
			
		||||
namespace Engine.Core.Debug;
 | 
			
		||||
 | 
			
		||||
public static class Assert
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Debug;
 | 
			
		||||
namespace Engine.Core.Debug;
 | 
			
		||||
 | 
			
		||||
public class ConsoleLogger : LoggerBase
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.IO;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Debug;
 | 
			
		||||
namespace Engine.Core.Debug;
 | 
			
		||||
 | 
			
		||||
public class FileLogger : LoggerBase
 | 
			
		||||
{
 | 
			
		||||
@@ -14,6 +14,9 @@ public class FileLogger : LoggerBase
 | 
			
		||||
 | 
			
		||||
    public FileLogger(string filePath)
 | 
			
		||||
    {
 | 
			
		||||
        if (!filePath.EndsWith(".log"))
 | 
			
		||||
            filePath += ".log";
 | 
			
		||||
 | 
			
		||||
        FilePath = filePath;
 | 
			
		||||
 | 
			
		||||
        bool isRelativePath = Path.GetFullPath(filePath).CompareTo(filePath) != 0;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Syntriax.Engine.Core.Debug;
 | 
			
		||||
namespace Engine.Core.Debug;
 | 
			
		||||
 | 
			
		||||
public interface ILogger
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Debug;
 | 
			
		||||
namespace Engine.Core.Debug;
 | 
			
		||||
 | 
			
		||||
public abstract class LoggerBase : ILogger
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Syntriax.Engine.Core.Debug;
 | 
			
		||||
namespace Engine.Core.Debug;
 | 
			
		||||
 | 
			
		||||
public class LoggerContainer : Behaviour, ILogger
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Debug;
 | 
			
		||||
namespace Engine.Core.Debug;
 | 
			
		||||
 | 
			
		||||
public static class LoggerExtensions
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Syntriax.Engine.Core.Debug;
 | 
			
		||||
namespace Engine.Core.Debug;
 | 
			
		||||
 | 
			
		||||
public class LoggerWrapper(ILogger firstLogger, ILogger secondLogger) : ILogger
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Syntriax.Engine.Core.Debug;
 | 
			
		||||
namespace Engine.Core.Debug;
 | 
			
		||||
 | 
			
		||||
public static class LoggerWrapperExtensions
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										71
									
								
								Engine.Core/Debug/RotatingFileLogger.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								Engine.Core/Debug/RotatingFileLogger.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,71 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
 | 
			
		||||
namespace Engine.Core.Debug;
 | 
			
		||||
 | 
			
		||||
public class RotatingFileLogger : ILogger
 | 
			
		||||
{
 | 
			
		||||
    public readonly FileLogger FileLogger = null!;
 | 
			
		||||
    public readonly string Directory = string.Empty;
 | 
			
		||||
    public readonly int RotateLength = 3;
 | 
			
		||||
 | 
			
		||||
    public RotatingFileLogger(string directory, string namePrefix, string nameSuffix = "", int rotateLength = 3)
 | 
			
		||||
    {
 | 
			
		||||
        RotateLength = rotateLength;
 | 
			
		||||
 | 
			
		||||
        string fileName = Path.Combine(directory, namePrefix);
 | 
			
		||||
        if (!string.IsNullOrWhiteSpace(nameSuffix))
 | 
			
		||||
            fileName += $"_{nameSuffix}";
 | 
			
		||||
 | 
			
		||||
        bool isRelativePath = Path.GetFullPath(fileName).CompareTo(fileName) != 0;
 | 
			
		||||
 | 
			
		||||
        if (isRelativePath)
 | 
			
		||||
            fileName = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName));
 | 
			
		||||
 | 
			
		||||
        if (File.Exists($"{fileName}.log"))
 | 
			
		||||
            RenameExistingLogs(fileName, RotateLength);
 | 
			
		||||
 | 
			
		||||
        FileLogger = new(fileName);
 | 
			
		||||
 | 
			
		||||
        Directory = Path.GetDirectoryName(fileName) ?? throw new("Unexpected error on getting directory of logger path");
 | 
			
		||||
        RotateLastLogs(Directory, namePrefix, RotateLength);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static void RenameExistingLogs(string filePath, int rotateLength)
 | 
			
		||||
    {
 | 
			
		||||
        for (int i = rotateLength - 1; i >= 0; i--)
 | 
			
		||||
        {
 | 
			
		||||
            string source = i == 0
 | 
			
		||||
                ? $"{filePath}.log"
 | 
			
		||||
                : $"{filePath}_{i}.log";
 | 
			
		||||
 | 
			
		||||
            string dest = $"{filePath}_{i + 1}.log";
 | 
			
		||||
 | 
			
		||||
            if (!File.Exists(source))
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            if (File.Exists(dest))
 | 
			
		||||
                File.Delete(dest);
 | 
			
		||||
 | 
			
		||||
            File.Move(source, dest);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static void RotateLastLogs(string directory, string prefix, int rotateLength)
 | 
			
		||||
    {
 | 
			
		||||
        IOrderedEnumerable<string> logs = System.IO.Directory.GetFiles(directory, $"{prefix}*.log")
 | 
			
		||||
            .OrderBy(File.GetCreationTime);
 | 
			
		||||
 | 
			
		||||
        foreach (string file in logs.Skip(rotateLength))
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                ILogger.Shared.Log($"Removing log file located at \"{file}\" during rotation.");
 | 
			
		||||
                File.Delete(file);
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception e) { ILogger.Shared.LogException($"Failed to rotate log file at \"{file}\"", e); }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ILogger.Level FilterLevel { get => FileLogger.FilterLevel; set => FileLogger.FilterLevel = value; }
 | 
			
		||||
    public void Log(string message, ILogger.Level level = ILogger.Level.Info, bool force = false) => FileLogger.Log(message, level, force);
 | 
			
		||||
}
 | 
			
		||||
@@ -4,7 +4,8 @@
 | 
			
		||||
    <TargetFramework>net9.0</TargetFramework>
 | 
			
		||||
    <ImplicitUsings>false</ImplicitUsings>
 | 
			
		||||
    <Nullable>enable</Nullable>
 | 
			
		||||
    <RootNamespace>Syntriax.Engine.Core</RootNamespace>
 | 
			
		||||
    <RootNamespace>Engine.Core</RootNamespace>
 | 
			
		||||
    <AssemblyName>Engine.Core</AssemblyName>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
</Project>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Exceptions;
 | 
			
		||||
namespace Engine.Core.Exceptions;
 | 
			
		||||
 | 
			
		||||
public class AssignFailedException(string? message) : Exception(message)
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,3 @@
 | 
			
		||||
namespace Syntriax.Engine.Core.Exceptions;
 | 
			
		||||
namespace Engine.Core.Exceptions;
 | 
			
		||||
 | 
			
		||||
public class BehaviourNotFoundException(string? message) : NotFoundException(message);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Exceptions;
 | 
			
		||||
namespace Engine.Core.Exceptions;
 | 
			
		||||
 | 
			
		||||
public class NotAssignedException(string? message) : Exception(message)
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Exceptions;
 | 
			
		||||
namespace Engine.Core.Exceptions;
 | 
			
		||||
 | 
			
		||||
public class NotFoundException(string? message) : Exception(message)
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,3 @@
 | 
			
		||||
namespace Syntriax.Engine.Core.Exceptions;
 | 
			
		||||
namespace Engine.Core.Exceptions;
 | 
			
		||||
 | 
			
		||||
public class UniverseObjectNotFoundException(string? message) : NotFoundException(message);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Diagnostics.CodeAnalysis;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core.Exceptions;
 | 
			
		||||
using Engine.Core.Exceptions;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
public static class BehaviourControllerExtensions
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
public static class EnumExtensions
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
public static class FloatExtensions
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
public static class TransformExtensions
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
using Syntriax.Engine.Core.Exceptions;
 | 
			
		||||
using Engine.Core.Exceptions;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
public static class UniverseExtensions
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Diagnostics.CodeAnalysis;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core.Exceptions;
 | 
			
		||||
using Engine.Core.Exceptions;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
public static class UniverseObjectExtensions
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Syntriax.Engine.Core.Factory.Abstract;
 | 
			
		||||
namespace Engine.Core.Factory.Abstract;
 | 
			
		||||
 | 
			
		||||
public interface IFactory<TInterface> where TInterface : class
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
using Syntriax.Engine.Core.Exceptions;
 | 
			
		||||
using Engine.Core.Exceptions;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Factory;
 | 
			
		||||
namespace Engine.Core.Factory;
 | 
			
		||||
 | 
			
		||||
public class BehaviourControllerFactory
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
using Syntriax.Engine.Core.Exceptions;
 | 
			
		||||
using Engine.Core.Exceptions;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Factory;
 | 
			
		||||
namespace Engine.Core.Factory;
 | 
			
		||||
 | 
			
		||||
public class BehaviourFactory
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Syntriax.Engine.Core.Factory.Abstract;
 | 
			
		||||
using Engine.Core.Factory.Abstract;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Factory;
 | 
			
		||||
namespace Engine.Core.Factory;
 | 
			
		||||
 | 
			
		||||
public abstract class FactoryBase<TInterface> : IFactory<TInterface>
 | 
			
		||||
    where TInterface : class
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
using Syntriax.Engine.Core.Exceptions;
 | 
			
		||||
using Engine.Core.Exceptions;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Factory;
 | 
			
		||||
namespace Engine.Core.Factory;
 | 
			
		||||
 | 
			
		||||
public class StateEnableFactory
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Syntriax.Engine.Core.Factory;
 | 
			
		||||
namespace Engine.Core.Factory;
 | 
			
		||||
 | 
			
		||||
public class TransformFactory
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@ using System.Collections.Concurrent;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Factory;
 | 
			
		||||
namespace Engine.Core.Factory;
 | 
			
		||||
 | 
			
		||||
public static class TypeFactory
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
using Syntriax.Engine.Core.Exceptions;
 | 
			
		||||
using Engine.Core.Exceptions;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Factory;
 | 
			
		||||
namespace Engine.Core.Factory;
 | 
			
		||||
 | 
			
		||||
public class UniverseObjectFactory
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,15 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core.Debug;
 | 
			
		||||
using Engine.Core.Debug;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
// TODO!: every reverse loop has a chance to have more than 1 unsubscription,
 | 
			
		||||
// for (int i = listeners.Count - 1; i >= 0; i--) 
 | 
			
		||||
// can be replaced with 
 | 
			
		||||
// for (int i = listeners.Count - 1; i >= 0; i = Math.Min(i - 1, listeners.Count - 1))
 | 
			
		||||
// but this would causes possible double calls on already called callbacks, find a better method.
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents a simple event with no parameters.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										102
									
								
								Engine.Core/Helpers/FastList.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								Engine.Core/Helpers/FastList.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,102 @@
 | 
			
		||||
using System.Collections;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
public class FastList<T> : IList<T>, IReadOnlyList<T>, IEnumerable<T> where T : notnull
 | 
			
		||||
{
 | 
			
		||||
    private readonly List<T> items = [];
 | 
			
		||||
    private readonly Dictionary<T, int> indexMap = [];
 | 
			
		||||
 | 
			
		||||
    public bool IsReadOnly { get; set; } = false;
 | 
			
		||||
    public int Count => items.Count;
 | 
			
		||||
    public T this[int index]
 | 
			
		||||
    {
 | 
			
		||||
        get => items[index];
 | 
			
		||||
        set
 | 
			
		||||
        {
 | 
			
		||||
            if (IsReadOnly)
 | 
			
		||||
                throw new System.Data.ReadOnlyException();
 | 
			
		||||
 | 
			
		||||
            items[index] = value;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void Add(T item)
 | 
			
		||||
    {
 | 
			
		||||
        if (IsReadOnly)
 | 
			
		||||
            throw new System.Data.ReadOnlyException();
 | 
			
		||||
 | 
			
		||||
        indexMap[item] = items.Count;
 | 
			
		||||
        items.Add(item);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void RemoveAt(int i) => Remove(items[i], i);
 | 
			
		||||
    public bool Remove(T item)
 | 
			
		||||
    {
 | 
			
		||||
        if (IsReadOnly)
 | 
			
		||||
            throw new System.Data.ReadOnlyException();
 | 
			
		||||
 | 
			
		||||
        if (!indexMap.TryGetValue(item, out int index))
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        Remove(item, index);
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void Remove(T item, int index)
 | 
			
		||||
    {
 | 
			
		||||
        int lastIndex = items.Count - 1;
 | 
			
		||||
        T lastItem = items[lastIndex];
 | 
			
		||||
 | 
			
		||||
        items[index] = lastItem;
 | 
			
		||||
        indexMap[lastItem] = index;
 | 
			
		||||
 | 
			
		||||
        items.RemoveAt(lastIndex);
 | 
			
		||||
        indexMap.Remove(item);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void Insert(int index, T item)
 | 
			
		||||
    {
 | 
			
		||||
        if (IsReadOnly)
 | 
			
		||||
            throw new System.Data.ReadOnlyException();
 | 
			
		||||
 | 
			
		||||
        items.Insert(index, item);
 | 
			
		||||
 | 
			
		||||
        for (int i = index; i < items.Count; i++)
 | 
			
		||||
            indexMap[items[i]] = i;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void Clear()
 | 
			
		||||
    {
 | 
			
		||||
        if (IsReadOnly)
 | 
			
		||||
            throw new System.Data.ReadOnlyException();
 | 
			
		||||
 | 
			
		||||
        items.Clear();
 | 
			
		||||
        indexMap.Clear();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool Contains(T item) => indexMap.ContainsKey(item);
 | 
			
		||||
    public int IndexOf(T item) => items.IndexOf(item);
 | 
			
		||||
    public int BinarySearch(T item, IComparer<T>? comparer = null) => items.BinarySearch(item, comparer);
 | 
			
		||||
 | 
			
		||||
    public void Sort(IComparer<T> comparer)
 | 
			
		||||
    {
 | 
			
		||||
        if (IsReadOnly)
 | 
			
		||||
            throw new System.Data.ReadOnlyException();
 | 
			
		||||
 | 
			
		||||
        items.Sort(comparer);
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < items.Count; i++)
 | 
			
		||||
            indexMap[items[i]] = i;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void CopyTo(T[] array, int arrayIndex) => items.CopyTo(array, arrayIndex);
 | 
			
		||||
 | 
			
		||||
    public IEnumerator<T> GetEnumerator() => items.GetEnumerator();
 | 
			
		||||
    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
 | 
			
		||||
 | 
			
		||||
    public FastList() { }
 | 
			
		||||
    public FastList(int count) { items.Capacity = count; }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										172
									
								
								Engine.Core/Helpers/FastListOrdered.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								Engine.Core/Helpers/FastListOrdered.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,172 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// TODO This is VEERY experimental, and doesn't work well with the indices access. Use with caution
 | 
			
		||||
/// </summary>
 | 
			
		||||
/// <typeparam name="TIndex"></typeparam>
 | 
			
		||||
/// <typeparam name="TItem"></typeparam>
 | 
			
		||||
public class FastListOrdered<TIndex, TItem> : IList<TItem>, IReadOnlyList<TItem>, IEnumerable<TItem> where TItem : notnull where TIndex : IComparable
 | 
			
		||||
{
 | 
			
		||||
    private readonly SortedDictionary<TIndex, FastList<TItem>> items = null!;
 | 
			
		||||
 | 
			
		||||
    private readonly Func<TItem, TIndex> getIndexFunc = null!;
 | 
			
		||||
    private readonly IComparer<TIndex> sortBy = null!;
 | 
			
		||||
 | 
			
		||||
    private int count = 0;
 | 
			
		||||
    public int Count => count;
 | 
			
		||||
 | 
			
		||||
    public bool IsReadOnly { get; set; } = false;
 | 
			
		||||
 | 
			
		||||
    public TItem this[int index]
 | 
			
		||||
    {
 | 
			
		||||
        get { (TIndex tIndex, int i) = GetAt(index); return items[tIndex][i]; }
 | 
			
		||||
        set
 | 
			
		||||
        {
 | 
			
		||||
            if (IsReadOnly)
 | 
			
		||||
                throw new System.Data.ReadOnlyException();
 | 
			
		||||
            (TIndex tIndex, int i) = GetAt(index); items[tIndex][i] = value;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private (TIndex TIndex, int i) GetAt(Index index)
 | 
			
		||||
    {
 | 
			
		||||
        int actualIndex = index.IsFromEnd
 | 
			
		||||
                ? count - index.Value
 | 
			
		||||
                : index.Value;
 | 
			
		||||
 | 
			
		||||
        if (actualIndex < 0 || actualIndex >= count)
 | 
			
		||||
            throw new IndexOutOfRangeException();
 | 
			
		||||
 | 
			
		||||
        int leftIndex = actualIndex;
 | 
			
		||||
        foreach ((TIndex i, FastList<TItem> list) in items)
 | 
			
		||||
        {
 | 
			
		||||
            if (leftIndex < list.Count)
 | 
			
		||||
                return (i, leftIndex);
 | 
			
		||||
            leftIndex -= list.Count;
 | 
			
		||||
        }
 | 
			
		||||
        throw new IndexOutOfRangeException();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int IndexOf(TItem item)
 | 
			
		||||
    {
 | 
			
		||||
        int indexCounter = 0;
 | 
			
		||||
        foreach ((TIndex index, FastList<TItem> list) in items)
 | 
			
		||||
        {
 | 
			
		||||
            int i = list.IndexOf(item);
 | 
			
		||||
            if (i != -1)
 | 
			
		||||
                return indexCounter + i;
 | 
			
		||||
            indexCounter += list.Count;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void Add(TItem item)
 | 
			
		||||
    {
 | 
			
		||||
        if (IsReadOnly)
 | 
			
		||||
            throw new System.Data.ReadOnlyException();
 | 
			
		||||
 | 
			
		||||
        TIndex key = getIndexFunc(item);
 | 
			
		||||
        if (!items.TryGetValue(key, out FastList<TItem>? list))
 | 
			
		||||
            items[key] = list = [];
 | 
			
		||||
 | 
			
		||||
        list.Add(item);
 | 
			
		||||
        count++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void Insert(int index, TItem item)
 | 
			
		||||
    {
 | 
			
		||||
        if (IsReadOnly)
 | 
			
		||||
            throw new System.Data.ReadOnlyException();
 | 
			
		||||
 | 
			
		||||
        TIndex tIndex = getIndexFunc(item);
 | 
			
		||||
        if (!items.TryGetValue(tIndex, out FastList<TItem>? list))
 | 
			
		||||
            items[tIndex] = list = [];
 | 
			
		||||
 | 
			
		||||
        list.Insert(index, item);
 | 
			
		||||
        count++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool Remove(TItem item)
 | 
			
		||||
    {
 | 
			
		||||
        if (IsReadOnly)
 | 
			
		||||
            throw new System.Data.ReadOnlyException();
 | 
			
		||||
 | 
			
		||||
        TIndex index = getIndexFunc(item);
 | 
			
		||||
        if (!items.TryGetValue(index, out FastList<TItem>? list))
 | 
			
		||||
            throw new Exceptions.NotFoundException($"Index of '{index}' is not found in the collector");
 | 
			
		||||
 | 
			
		||||
        if (!list.Remove(item))
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        count--;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void RemoveAt(int index)
 | 
			
		||||
    {
 | 
			
		||||
        if (IsReadOnly)
 | 
			
		||||
            throw new System.Data.ReadOnlyException();
 | 
			
		||||
 | 
			
		||||
        (TIndex tIndex, int i) = GetAt(index);
 | 
			
		||||
        items[tIndex].RemoveAt(i);
 | 
			
		||||
        count--;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void Clear()
 | 
			
		||||
    {
 | 
			
		||||
        if (IsReadOnly)
 | 
			
		||||
            throw new System.Data.ReadOnlyException();
 | 
			
		||||
 | 
			
		||||
        foreach ((TIndex index, FastList<TItem> list) in items)
 | 
			
		||||
            list.Clear();
 | 
			
		||||
 | 
			
		||||
        count = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool Contains(TItem item)
 | 
			
		||||
    {
 | 
			
		||||
        foreach ((TIndex index, FastList<TItem> list) in items)
 | 
			
		||||
            if (list.Contains(item))
 | 
			
		||||
                return true;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void CopyTo(TItem[] array, int arrayIndex)
 | 
			
		||||
    {
 | 
			
		||||
        int indexCounter = 0;
 | 
			
		||||
 | 
			
		||||
        foreach ((TIndex index, FastList<TItem> list) in items)
 | 
			
		||||
        {
 | 
			
		||||
            list.CopyTo(array, indexCounter);
 | 
			
		||||
            indexCounter += list.Count;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public IEnumerator<TItem> GetEnumerator()
 | 
			
		||||
    {
 | 
			
		||||
        foreach ((TIndex index, FastList<TItem> list) in items)
 | 
			
		||||
            foreach (TItem item in list)
 | 
			
		||||
                yield return item;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
 | 
			
		||||
 | 
			
		||||
    public FastListOrdered(Func<TItem, TIndex> getIndexFunc, Comparison<TIndex> sortBy)
 | 
			
		||||
    {
 | 
			
		||||
        this.getIndexFunc = getIndexFunc;
 | 
			
		||||
        this.sortBy = Comparer<TIndex>.Create(sortBy);
 | 
			
		||||
        items = new(this.sortBy);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public FastListOrdered(Func<TItem, TIndex> getIndexFunc, IComparer<TIndex> sortBy)
 | 
			
		||||
    {
 | 
			
		||||
        this.getIndexFunc = getIndexFunc;
 | 
			
		||||
        this.sortBy = sortBy;
 | 
			
		||||
        items = new(sortBy);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
public interface IPool<T>
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
public class ListPool<T> : IPool<List<T>>
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
public class Pool<T> : IPool<T>
 | 
			
		||||
{
 | 
			
		||||
@@ -10,22 +10,25 @@ public class Pool<T> : IPool<T>
 | 
			
		||||
 | 
			
		||||
    private readonly Func<T> generator = null!;
 | 
			
		||||
    private readonly Queue<T> queue = new();
 | 
			
		||||
    private readonly HashSet<T> queuedHashes = [];
 | 
			
		||||
 | 
			
		||||
    public T Get()
 | 
			
		||||
    {
 | 
			
		||||
        if (!queue.TryDequeue(out T? result))
 | 
			
		||||
            result = generator();
 | 
			
		||||
 | 
			
		||||
        queuedHashes.Remove(result);
 | 
			
		||||
        OnRemoved?.Invoke(this, result);
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void Return(T item)
 | 
			
		||||
    {
 | 
			
		||||
        if (queue.Contains(item))
 | 
			
		||||
        if (queuedHashes.Contains(item))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        queue.Enqueue(item);
 | 
			
		||||
        queuedHashes.Add(item);
 | 
			
		||||
        OnReturned?.Invoke(this, item);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
public interface IProgressionTracker : IReadOnlyProgressionTracker
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
public interface IReadOnlyProgressionTracker
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
public class ProgressionTracker : IProgressionTracker
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
public record struct ProgressiveTask<T>(IReadOnlyProgressionTracker ProgressionTracker, Task<T> Task)
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Numerics;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
public static class Math
 | 
			
		||||
{
 | 
			
		||||
@@ -240,21 +240,33 @@ public static class Math
 | 
			
		||||
    public static T Lerp<T>(T x, T y, T t) where T : IFloatingPoint<T> => x + (y - x) * t;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Rounds a number to a specified number of fractional digits.
 | 
			
		||||
    /// Rounds a number to the closest integer.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="x">The number to round.</param>
 | 
			
		||||
    /// <param name="digits">The number of fractional digits in the return value.</param>
 | 
			
		||||
    /// <param name="mode">Specification for how to round <paramref name="x"/> if it is midway between two other numbers.</param>
 | 
			
		||||
    /// <returns>The number <paramref name="x"/> rounded to <paramref name="digits"/> fractional digits.</returns>
 | 
			
		||||
    public static float Round(float x, int digits, MidpointRounding mode) => MathF.Round(x, digits, mode);
 | 
			
		||||
    /// <param name="roundMode">Specification for how to round <paramref name="x"/> if it is midway between two other numbers.</param>
 | 
			
		||||
    /// <returns>The number <paramref name="x"/> rounded to the closest integer.</returns>
 | 
			
		||||
    public static float Round(float x, RoundMode roundMode) => RoundToInt(x, roundMode);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Rounds a number to an integer.
 | 
			
		||||
    /// Rounds a number to the closest integer.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="x">The number to round.</param>
 | 
			
		||||
    /// <param name="roundMode">Specification for how to round <paramref name="x"/> if it's midway between two numbers</param>
 | 
			
		||||
    /// <returns></returns>
 | 
			
		||||
    public static int RoundToInt(float x, RoundMode roundMode = RoundMode.Ceil) => (int)MathF.Round(x, 0, roundMode == RoundMode.Ceil ? MidpointRounding.ToPositiveInfinity : MidpointRounding.ToNegativeInfinity);
 | 
			
		||||
    /// <returns>The number <paramref name="x"/> rounded to the closest integer.</returns>
 | 
			
		||||
    public static int RoundToInt(float x, RoundMode roundMode = RoundMode.Ceil)
 | 
			
		||||
    {
 | 
			
		||||
        float remainder = x.Mod(1f);
 | 
			
		||||
 | 
			
		||||
        if (remainder == .5f)
 | 
			
		||||
            if (roundMode == RoundMode.Floor)
 | 
			
		||||
                return (int)x;
 | 
			
		||||
            else
 | 
			
		||||
                return (int)(x + .5f);
 | 
			
		||||
 | 
			
		||||
        if (x < 0f)
 | 
			
		||||
            return (int)(x - .5f);
 | 
			
		||||
        return (int)(x + .5f);
 | 
			
		||||
    }
 | 
			
		||||
    public enum RoundMode { Ceil, Floor };
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Numerics;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
public static class MathExtensions
 | 
			
		||||
{
 | 
			
		||||
@@ -81,7 +81,7 @@ public static class MathExtensions
 | 
			
		||||
    public static T Lerp<T>(this T x, T y, T t) where T : IFloatingPoint<T> => Math.Lerp(x, y, t);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Math.Round(float, int, MidpointRounding)" />
 | 
			
		||||
    public static float Round(this float x, int digits, MidpointRounding mode) => Math.Round(x, digits, mode);
 | 
			
		||||
    public static float Round(this float x, Math.RoundMode mode) => Math.Round(x, mode);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Math.RoundToInt(float, Math.RoundMode)" />
 | 
			
		||||
    public static int RoundToInt(this float x, Math.RoundMode roundMode = Math.RoundMode.Ceil) => Math.RoundToInt(x, roundMode);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Syntriax.Engine.Core
 | 
			
		||||
namespace Engine.Core
 | 
			
		||||
{
 | 
			
		||||
    // This is pretty much so the assembly gets loaded automatically because 
 | 
			
		||||
    // the builds include the assembly but sometimes doesn't link load it at startup.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents an Axis-Aligned Bounding Box (AABB) in 2D space.
 | 
			
		||||
@@ -11,7 +12,7 @@ namespace Syntriax.Engine.Core;
 | 
			
		||||
/// Initializes a new instance of the <see cref="AABB"/> struct with the specified lower and upper boundaries.
 | 
			
		||||
/// </remarks>
 | 
			
		||||
[System.Diagnostics.DebuggerDisplay("LowerBoundary: {LowerBoundary.ToString(), nq}, UpperBoundary: {UpperBoundary.ToString(), nq}")]
 | 
			
		||||
public readonly struct AABB(Vector2D lowerBoundary, Vector2D upperBoundary)
 | 
			
		||||
public readonly struct AABB(Vector2D lowerBoundary, Vector2D upperBoundary) : IEquatable<AABB>
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The lower boundary of the <see cref="AABB"/>.
 | 
			
		||||
@@ -82,6 +83,7 @@ public readonly struct AABB(Vector2D lowerBoundary, Vector2D upperBoundary)
 | 
			
		||||
    /// <param name="obj">The object to compare with the current <see cref="AABB"/>.</param>
 | 
			
		||||
    /// <returns><see cref="true"/> if the specified object is equal to the current <see cref="AABB"/>; otherwise, <see cref="false"/>.</returns>
 | 
			
		||||
    public override bool Equals(object? obj) => obj is AABB aabb && this == aabb;
 | 
			
		||||
    public bool Equals(AABB other) => this == other;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Generates a hash code for the <see cref="AABB"/>.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents a 2D circle.
 | 
			
		||||
@@ -11,7 +12,7 @@ namespace Syntriax.Engine.Core;
 | 
			
		||||
/// Initializes a new instance of the <see cref="Circle"/> struct with the specified center and radius.
 | 
			
		||||
/// </remarks>
 | 
			
		||||
[DebuggerDisplay("Center: {Center.ToString(),nq}, Radius: {Radius}")]
 | 
			
		||||
public readonly struct Circle(Vector2D center, float radius)
 | 
			
		||||
public readonly struct Circle(Vector2D center, float radius) : IEquatable<Circle>
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The center of the circle.
 | 
			
		||||
@@ -87,6 +88,7 @@ public readonly struct Circle(Vector2D center, float radius)
 | 
			
		||||
    /// <param name="obj">The object to compare with the current <see cref="Circle"/>.</param>
 | 
			
		||||
    /// <returns><see cref="true"/> if the specified object is equal to the current <see cref="Circle"/>; otherwise, <see cref="false"/>.</returns>
 | 
			
		||||
    public override bool Equals(object? obj) => obj is Circle circle && this == circle;
 | 
			
		||||
    public bool Equals(Circle other) => this == other;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Generates a hash code for the <see cref="Circle"/>.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,6 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents an HSV color.
 | 
			
		||||
@@ -10,7 +12,7 @@ namespace Syntriax.Engine.Core;
 | 
			
		||||
/// Initializes a new instance of the <see cref="ColorHSV"/> struct with the specified values.
 | 
			
		||||
/// </remarks>
 | 
			
		||||
[System.Diagnostics.DebuggerDisplay("{ToString(),nq}")]
 | 
			
		||||
public readonly struct ColorHSV(float hue, float saturation, float value)
 | 
			
		||||
public readonly struct ColorHSV(float hue, float saturation, float value) : IEquatable<ColorHSV>
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The Hue value of the <see cref="ColorHSV"/>.
 | 
			
		||||
@@ -112,6 +114,7 @@ public readonly struct ColorHSV(float hue, float saturation, float value)
 | 
			
		||||
    /// <param name="obj">The object to compare with the current <see cref="ColorHSV"/>.</param>
 | 
			
		||||
    /// <returns><see cref="true"/> if the specified object is equal to the current <see cref="ColorHSV"/>; otherwise, <see cref="false"/>.</returns>
 | 
			
		||||
    public override bool Equals(object? obj) => obj is ColorHSV colorHSV && this == colorHSV;
 | 
			
		||||
    public bool Equals(ColorHSV other) => this == other;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Generates a hash code for the <see cref="ColorHSV"/>.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,6 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents an HSV color.
 | 
			
		||||
@@ -11,7 +13,7 @@ namespace Syntriax.Engine.Core;
 | 
			
		||||
/// Initializes a new instance of the <see cref="ColorHSVA"/> struct with the specified values.
 | 
			
		||||
/// </remarks>
 | 
			
		||||
[System.Diagnostics.DebuggerDisplay("{ToString(),nq}")]
 | 
			
		||||
public readonly struct ColorHSVA(float hue, float saturation, float value, float alpha = 1)
 | 
			
		||||
public readonly struct ColorHSVA(float hue, float saturation, float value, float alpha = 1) : IEquatable<ColorHSVA>
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The Hue value of the <see cref="ColorHSVA"/>.
 | 
			
		||||
@@ -150,6 +152,7 @@ public readonly struct ColorHSVA(float hue, float saturation, float value, float
 | 
			
		||||
    /// <param name="obj">The object to compare with the current <see cref="ColorHSVA"/>.</param>
 | 
			
		||||
    /// <returns><see cref="true"/> if the specified object is equal to the current <see cref="ColorHSVA"/>; otherwise, <see cref="false"/>.</returns>
 | 
			
		||||
    public override bool Equals(object? obj) => obj is ColorHSVA colorHSVA && this == colorHSVA;
 | 
			
		||||
    public bool Equals(ColorHSVA other) => this == other;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Generates a hash code for the <see cref="ColorHSVA"/>.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,6 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents an RGB color.
 | 
			
		||||
@@ -10,7 +12,7 @@ namespace Syntriax.Engine.Core;
 | 
			
		||||
/// Initializes a new instance of the <see cref="ColorRGB"/> struct with the specified values.
 | 
			
		||||
/// </remarks>
 | 
			
		||||
[System.Diagnostics.DebuggerDisplay("{ToString(),nq}")]
 | 
			
		||||
public readonly struct ColorRGB(byte r, byte g, byte b)
 | 
			
		||||
public readonly struct ColorRGB(byte r, byte g, byte b) : IEquatable<ColorRGB>
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The Red value of the <see cref="ColorRGB"/>.
 | 
			
		||||
@@ -102,6 +104,7 @@ public readonly struct ColorRGB(byte r, byte g, byte b)
 | 
			
		||||
    /// <param name="obj">The object to compare with the current <see cref="ColorRGB"/>.</param>
 | 
			
		||||
    /// <returns><see cref="true"/> if the specified object is equal to the current <see cref="ColorRGB"/>; otherwise, <see cref="false"/>.</returns>
 | 
			
		||||
    public override bool Equals(object? obj) => obj is ColorRGB colorRGB && this == colorRGB;
 | 
			
		||||
    public bool Equals(ColorRGB other) => this == other;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Generates a hash code for the <see cref="ColorRGB"/>.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,6 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents an RGBA color.
 | 
			
		||||
@@ -11,7 +13,7 @@ namespace Syntriax.Engine.Core;
 | 
			
		||||
/// Initializes a new instance of the <see cref="ColorRGBA"/> struct with the specified values.
 | 
			
		||||
/// </remarks>
 | 
			
		||||
[System.Diagnostics.DebuggerDisplay("{ToString(),nq}")]
 | 
			
		||||
public readonly struct ColorRGBA(byte r, byte g, byte b, byte a = 255)
 | 
			
		||||
public readonly struct ColorRGBA(byte r, byte g, byte b, byte a = 255) : IEquatable<ColorRGBA>
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The Red value of the <see cref="ColorRGBA"/>.
 | 
			
		||||
@@ -132,6 +134,7 @@ public readonly struct ColorRGBA(byte r, byte g, byte b, byte a = 255)
 | 
			
		||||
    /// <param name="obj">The object to compare with the current <see cref="ColorRGBA"/>.</param>
 | 
			
		||||
    /// <returns><see cref="true"/> if the specified object is equal to the current <see cref="ColorRGBA"/>; otherwise, <see cref="false"/>.</returns>
 | 
			
		||||
    public override bool Equals(object? obj) => obj is ColorRGBA colorRGBA && this == colorRGBA;
 | 
			
		||||
    public bool Equals(ColorRGBA other) => this == other;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Generates a hash code for the <see cref="ColorRGBA"/>.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Diagnostics.CodeAnalysis;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents a 2D line segment defined by two endpoints.
 | 
			
		||||
@@ -11,7 +12,7 @@ namespace Syntriax.Engine.Core;
 | 
			
		||||
/// Initializes a new instance of the <see cref="Line2D"/> struct with the specified endpoints.
 | 
			
		||||
/// </remarks>
 | 
			
		||||
[System.Diagnostics.DebuggerDisplay("From: {From.ToString(),nq}, To: {To.ToString(),nq}, Direction: {Direction.ToString(),nq}, Length: {Length}")]
 | 
			
		||||
public readonly struct Line2D(Vector2D from, Vector2D to)
 | 
			
		||||
public readonly struct Line2D(Vector2D from, Vector2D to) : IEquatable<Line2D>
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The starting point of the <see cref="Line2D"/> segment.
 | 
			
		||||
@@ -196,6 +197,7 @@ public readonly struct Line2D(Vector2D from, Vector2D to)
 | 
			
		||||
    /// <param name="obj">The object to compare with the current <see cref="Line2D"/>.</param>
 | 
			
		||||
    /// <returns><see cref="true"/> if the specified object is equal to the current <see cref="Line2D"/>; otherwise, <see cref="false"/>.</returns>
 | 
			
		||||
    public override bool Equals(object? obj) => obj is Line2D line2D && this == line2D;
 | 
			
		||||
    public bool Equals(Line2D other) => this == other;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Generates a hash code for the <see cref="Line2D"/>.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,6 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents a <see cref="Line2DEquation"/> in the form y = mx + b.
 | 
			
		||||
@@ -9,7 +11,7 @@ namespace Syntriax.Engine.Core;
 | 
			
		||||
/// Initializes a new instance of the <see cref="Line2DEquation"/> struct with the specified slope and Y intercept.
 | 
			
		||||
/// </remarks>
 | 
			
		||||
[System.Diagnostics.DebuggerDisplay("y = {Slope}x + {OffsetY}")]
 | 
			
		||||
public readonly struct Line2DEquation(float slope, float offsetY)
 | 
			
		||||
public readonly struct Line2DEquation(float slope, float offsetY) : IEquatable<Line2DEquation>
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The slope of the <see cref="Line2DEquation"/>.
 | 
			
		||||
@@ -48,6 +50,7 @@ public readonly struct Line2DEquation(float slope, float offsetY)
 | 
			
		||||
    /// <param name="obj">The object to compare with the current <see cref="Line2DEquation"/>.</param>
 | 
			
		||||
    /// <returns><see cref="true"/> if the specified object is equal to the current <see cref="Line2DEquation"/>; otherwise, <see cref="false"/>.</returns>
 | 
			
		||||
    public override bool Equals(object? obj) => obj is Line2DEquation lineEquation && this == lineEquation;
 | 
			
		||||
    public bool Equals(Line2DEquation other) => this == other;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Generates a hash code for the <see cref="Line2DEquation"/>.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,6 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents a range of values along a single axis.
 | 
			
		||||
@@ -9,7 +11,7 @@ namespace Syntriax.Engine.Core;
 | 
			
		||||
/// Initializes a new instance of the <see cref="Projection1D"/> struct with the specified minimum and maximum values.
 | 
			
		||||
/// </remarks>
 | 
			
		||||
[System.Diagnostics.DebuggerDisplay("Min: {Min}, Max: {Max}")]
 | 
			
		||||
public readonly struct Projection1D(float min, float max)
 | 
			
		||||
public readonly struct Projection1D(float min, float max) : IEquatable<Projection1D>
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Gets the minimum value of the projection.
 | 
			
		||||
@@ -90,6 +92,7 @@ public readonly struct Projection1D(float min, float max)
 | 
			
		||||
    /// <param name="obj">The object to compare with the current <see cref="Projection1D"/>.</param>
 | 
			
		||||
    /// <returns><see cref="true"/> if the specified object is equal to the current <see cref="Projection1D"/>; otherwise, <see cref="false"/>.</returns>
 | 
			
		||||
    public override bool Equals(object? obj) => obj is Projection1D projection1D && this == projection1D;
 | 
			
		||||
    public bool Equals(Projection1D other) => this == other;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Generates a hash code for the <see cref="Projection1D"/>.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,6 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents a 3D space rotation.
 | 
			
		||||
@@ -11,7 +13,7 @@ namespace Syntriax.Engine.Core;
 | 
			
		||||
/// Initializes a new instance of the <see cref="Quaternion"/> struct with the specified positions.
 | 
			
		||||
/// </remarks>
 | 
			
		||||
[System.Diagnostics.DebuggerDisplay("{ToString(),nq}, Length: {Magnitude}, LengthSquared: {MagnitudeSquared}, Normalized: {Normalized.ToString(),nq}")]
 | 
			
		||||
public readonly struct Quaternion(float x, float y, float z, float w)
 | 
			
		||||
public readonly struct Quaternion(float x, float y, float z, float w) : IEquatable<Quaternion>
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The X(i) imaginary of the <see cref="Quaternion"/>.
 | 
			
		||||
@@ -288,6 +290,7 @@ public readonly struct Quaternion(float x, float y, float z, float w)
 | 
			
		||||
    /// <param name="obj">The object to compare with the current <see cref="Quaternion"/>.</param>
 | 
			
		||||
    /// <returns><see cref="true"/> if the specified object is equal to the current <see cref="Quaternion"/>; otherwise, <see cref="false"/>.</returns>
 | 
			
		||||
    public override bool Equals(object? obj) => obj is Quaternion quaternion && this == quaternion;
 | 
			
		||||
    public bool Equals(Quaternion other) => this == other;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Generates a hash code for the <see cref="Quaternion"/>.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,13 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents an infinite ray in 2D space.
 | 
			
		||||
/// </summary>
 | 
			
		||||
/// <param name="Origin">The <see cref="Vector2D"/> in 2D space where the ray starts from.</param>
 | 
			
		||||
/// <param name="Direction">Normalized <see cref="Vector2D"/> indicating the ray's is direction.</param> 
 | 
			
		||||
public readonly struct Ray2D(Vector2D Origin, Vector2D Direction)
 | 
			
		||||
public readonly struct Ray2D(Vector2D Origin, Vector2D Direction) : IEquatable<Ray2D>
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The starting point of the <see cref="Ray2D"/>.
 | 
			
		||||
@@ -72,6 +74,7 @@ public readonly struct Ray2D(Vector2D Origin, Vector2D Direction)
 | 
			
		||||
    /// <param name="obj">The object to compare with the current <see cref="Ray2D"/>.</param>
 | 
			
		||||
    /// <returns><see cref="true"/> if the specified object is equal to the current <see cref="Ray2D"/>; otherwise, <see cref="false"/>.</returns>
 | 
			
		||||
    public override bool Equals(object? obj) => obj is Ray2D ray2D && this == ray2D;
 | 
			
		||||
    public bool Equals(Ray2D other) => this == other;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Generates a hash code for the <see cref="Ray2D"/>.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
using System.Collections;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents a shape defined by a collection of vertices.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,9 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
[System.Diagnostics.DebuggerDisplay("A: {A.ToString(), nq}, B: {B.ToString(), nq}, B: {C.ToString(), nq}")]
 | 
			
		||||
public readonly struct Triangle(Vector2D A, Vector2D B, Vector2D C)
 | 
			
		||||
public readonly struct Triangle(Vector2D A, Vector2D B, Vector2D C) : IEquatable<Triangle>
 | 
			
		||||
{
 | 
			
		||||
    public readonly Vector2D A { get; init; } = A;
 | 
			
		||||
    public readonly Vector2D B { get; init; } = B;
 | 
			
		||||
@@ -54,6 +56,7 @@ public readonly struct Triangle(Vector2D A, Vector2D B, Vector2D C)
 | 
			
		||||
    /// <param name="obj">The object to compare with the current <see cref="Triangle"/>.</param>
 | 
			
		||||
    /// <returns><see cref="true"/> if the specified object is equal to the current <see cref="Triangle"/>; otherwise, <see cref="false"/>.</returns>
 | 
			
		||||
    public override bool Equals(object? obj) => obj is Triangle triangle && this == triangle;
 | 
			
		||||
    public bool Equals(Triangle other) => this == other;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Generates a hash code for the <see cref="Triangle"/>.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,6 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents a two-dimensional vector.
 | 
			
		||||
@@ -9,7 +11,7 @@ namespace Syntriax.Engine.Core;
 | 
			
		||||
/// Initializes a new instance of the <see cref="Vector2D"/> struct with the specified positions.
 | 
			
		||||
/// </remarks>
 | 
			
		||||
[System.Diagnostics.DebuggerDisplay("{ToString(),nq}, Length: {Magnitude}, LengthSquared: {MagnitudeSquared}, Normalized: {Normalized.ToString(),nq}")]
 | 
			
		||||
public readonly struct Vector2D(float x, float y)
 | 
			
		||||
public readonly struct Vector2D(float x, float y) : IEquatable<Vector2D>
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The X coordinate of the <see cref="Vector2D"/>.
 | 
			
		||||
@@ -82,6 +84,7 @@ public readonly struct Vector2D(float x, float y)
 | 
			
		||||
 | 
			
		||||
    public static implicit operator System.Numerics.Vector2(Vector2D vector) => new(vector.X, vector.Y);
 | 
			
		||||
    public static implicit operator Vector2D(System.Numerics.Vector2 vector) => new(vector.X, vector.Y);
 | 
			
		||||
    public static implicit operator Vector2D(Vector2DInt vector) => new(vector.X, vector.Y);
 | 
			
		||||
    public static implicit operator Vector2D(Vector3D vector) => new(vector.X, vector.Y);
 | 
			
		||||
    public static implicit operator Vector2D(System.Numerics.Vector3 vector) => new(vector.X, vector.Y);
 | 
			
		||||
 | 
			
		||||
@@ -308,6 +311,7 @@ public readonly struct Vector2D(float x, float y)
 | 
			
		||||
    /// <param name="obj">The object to compare with the current <see cref="Vector2D"/>.</param>
 | 
			
		||||
    /// <returns><see cref="true"/> if the specified object is equal to the current <see cref="Vector2D"/>; otherwise, <see cref="false"/>.</returns>
 | 
			
		||||
    public override bool Equals(object? obj) => obj is Vector2D vector2D && this == vector2D;
 | 
			
		||||
    public bool Equals(Vector2D other) => this == other;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Generates a hash code for the <see cref="Vector2D"/>.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										306
									
								
								Engine.Core/Primitives/Vector2DInt.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										306
									
								
								Engine.Core/Primitives/Vector2DInt.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,306 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents a two-dimensional integer vector.
 | 
			
		||||
/// </summary>
 | 
			
		||||
/// <param name="x">X position of the <see cref="Vector2DInt"/>.</param>
 | 
			
		||||
/// <param name="y">Y position of the <see cref="Vector2DInt"/>.</param>
 | 
			
		||||
/// <remarks>
 | 
			
		||||
/// Initializes a new instance of the <see cref="Vector2DInt"/> struct with the specified positions.
 | 
			
		||||
/// </remarks>
 | 
			
		||||
[System.Diagnostics.DebuggerDisplay("{ToString(),nq}")]
 | 
			
		||||
public readonly struct Vector2DInt(int x, int y) : IEquatable<Vector2DInt>
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The X coordinate of the <see cref="Vector2DInt"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public readonly int X = x;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The Y coordinate of the <see cref="Vector2DInt"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public readonly int Y = y;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The magnitude (length) of the <see cref="Vector2DInt"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public float Magnitude => Length(this);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The squared magnitude (length) of the <see cref="Vector2DInt"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public float MagnitudeSquared => LengthSquared(this);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Gets a <see cref="Vector2DInt"/> with the direction reversed.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public readonly Vector2DInt Reversed => -this;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Represents the unit <see cref="Vector2DInt"/> pointing upwards.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public readonly static Vector2DInt Up = new(0, 1);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Represents the unit <see cref="Vector2DInt"/> pointing downwards.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public readonly static Vector2DInt Down = new(0, -1);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Represents the unit <see cref="Vector2DInt"/> pointing leftwards.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public readonly static Vector2DInt Left = new(-1, 0);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Represents the unit <see cref="Vector2DInt"/> pointing rightwards.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public readonly static Vector2DInt Right = new(1, 0);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Represents the zero <see cref="Vector2DInt"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public readonly static Vector2DInt Zero = new(0, 0);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Represents the <see cref="Vector2DInt"/> with both components equal to 1.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public readonly static Vector2DInt One = new(1, 1);
 | 
			
		||||
 | 
			
		||||
    public static Vector2DInt operator -(Vector2DInt vector) => new(0 - vector.X, 0 - vector.Y);
 | 
			
		||||
    public static Vector2DInt operator +(Vector2DInt left, Vector2DInt right) => new(left.X + right.X, left.Y + right.Y);
 | 
			
		||||
    public static Vector2DInt operator -(Vector2DInt left, Vector2DInt right) => new(left.X - right.X, left.Y - right.Y);
 | 
			
		||||
    public static Vector2DInt operator *(Vector2DInt vector, int value) => new(vector.X * value, vector.Y * value);
 | 
			
		||||
    public static Vector2DInt operator *(int value, Vector2DInt vector) => new(vector.X * value, vector.Y * value);
 | 
			
		||||
    public static Vector2DInt operator /(Vector2DInt vector, int value) => new(vector.X / value, vector.Y / value);
 | 
			
		||||
    public static bool operator ==(Vector2DInt left, Vector2DInt right) => left.X == right.X && left.Y == right.Y;
 | 
			
		||||
    public static bool operator !=(Vector2DInt left, Vector2DInt right) => left.X != right.X || left.Y != right.Y;
 | 
			
		||||
 | 
			
		||||
    public static implicit operator Vector2DInt(Vector2D vector) => new(vector.X.RoundToInt(), vector.Y.RoundToInt());
 | 
			
		||||
    public static implicit operator Vector2DInt(Vector3DInt vector) => new(vector.X, vector.Y);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Calculates the length of the <see cref="Vector2DInt"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="vector">The <see cref="Vector2DInt"/>.</param>
 | 
			
		||||
    /// <returns>The length of the <see cref="Vector2DInt"/>.</returns>
 | 
			
		||||
    public static float Length(Vector2DInt vector) => Engine.Core.Math.Sqrt(LengthSquared(vector));
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Calculates the squared length of the <see cref="Vector2DInt"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="vector">The <see cref="Vector2DInt"/>.</param>
 | 
			
		||||
    /// <returns>The squared length of the <see cref="Vector2DInt"/>.</returns>
 | 
			
		||||
    public static float LengthSquared(Vector2DInt vector) => vector.X * vector.X + vector.Y * vector.Y;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Calculates the distance between two <see cref="Vector2DInt"/>s.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="from">The start <see cref="Vector2DInt"/>.</param>
 | 
			
		||||
    /// <param name="to">The end <see cref="Vector2DInt"/>.</param>
 | 
			
		||||
    /// <returns>The distance between the two <see cref="Vector2DInt"/>s.</returns>
 | 
			
		||||
    public static float Distance(Vector2DInt from, Vector2DInt to) => Length(FromTo(from, to));
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Inverts the direction of the <see cref="Vector2DInt"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="vector">The <see cref="Vector2DInt"/>.</param>
 | 
			
		||||
    /// <returns>The inverted <see cref="Vector2DInt"/>.</returns>
 | 
			
		||||
    public static Vector2DInt Invert(Vector2DInt vector) => -vector;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Adds two <see cref="Vector2DInt"/>s.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="left">The first <see cref="Vector2DInt"/>.</param>
 | 
			
		||||
    /// <param name="right">The second <see cref="Vector2DInt"/>.</param>
 | 
			
		||||
    /// <returns>The sum of the two <see cref="Vector2DInt"/>s.</returns>
 | 
			
		||||
    public static Vector2DInt Add(Vector2DInt left, Vector2DInt right) => left + right;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Subtracts one <see cref="Vector2DInt"/> from another.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="left">The <see cref="Vector2DInt"/> to subtract from.</param>
 | 
			
		||||
    /// <param name="right">The <see cref="Vector2DInt"/> to subtract.</param>
 | 
			
		||||
    /// <returns>The result of subtracting the second <see cref="Vector2DInt"/> from the first.</returns>
 | 
			
		||||
    public static Vector2DInt Subtract(Vector2DInt left, Vector2DInt right) => left - right;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Multiplies a <see cref="Vector2DInt"/> by a scalar value.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="vector">The <see cref="Vector2DInt"/>.</param>
 | 
			
		||||
    /// <param name="value">The scalar value.</param>
 | 
			
		||||
    /// <returns>The result of multiplying the <see cref="Vector2DInt"/> by the scalar value.</returns>
 | 
			
		||||
    public static Vector2DInt Multiply(Vector2DInt vector, int value) => vector * value;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Divides a <see cref="Vector2DInt"/> by a scalar value.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="vector">The <see cref="Vector2DInt"/>.</param>
 | 
			
		||||
    /// <param name="value">The scalar value.</param>
 | 
			
		||||
    /// <returns>The result of dividing the <see cref="Vector2DInt"/> by the scalar value.</returns>
 | 
			
		||||
    public static Vector2DInt Divide(Vector2DInt vector, int value) => vector / value;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Calculates the absolute value of each component of the vector.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="vector">The <see cref="Vector2DInt"/>.</param>
 | 
			
		||||
    /// <returns>The <see cref="Vector2DInt"/> with each component's absolute value.</returns>
 | 
			
		||||
    public static Vector2DInt Abs(Vector2DInt vector) => new(Engine.Core.Math.Abs(vector.X), Engine.Core.Math.Abs(vector.Y));
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Calculates the <see cref="Vector2DInt"/> from one point to another.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="from">The starting point.</param>
 | 
			
		||||
    /// <param name="to">The ending point.</param>
 | 
			
		||||
    /// <returns>The <see cref="Vector2DInt"/> from the starting point to the ending point.</returns>
 | 
			
		||||
    public static Vector2DInt FromTo(Vector2DInt from, Vector2DInt to) => to - from;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Scales a <see cref="Vector2DInt"/> by another <see cref="Vector2DInt"/> component-wise.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="vector">The <see cref="Vector2DInt"/> to scale.</param>
 | 
			
		||||
    /// <param name="scale">The <see cref="Vector2DInt"/> containing the scaling factors for each component.</param>
 | 
			
		||||
    /// <returns>The scaled <see cref="Vector2DInt"/>.</returns>
 | 
			
		||||
    public static Vector2DInt Scale(Vector2DInt vector, Vector2DInt scale) => new(vector.X * scale.X, vector.Y * scale.Y);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Calculates a perpendicular <see cref="Vector2DInt"/> to the given <see cref="Vector2DInt"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="vector">The input <see cref="Vector2DInt"/>.</param>
 | 
			
		||||
    /// <returns>A <see cref="Vector2DInt"/> perpendicular to the input <see cref="Vector2DInt"/>.</returns>
 | 
			
		||||
    public static Vector2DInt Perpendicular(Vector2DInt vector) => new(-vector.Y, vector.X);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Returns the component-wise minimum of two <see cref="Vector2DInt"/>s.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="left">The first <see cref="Vector2DInt"/>.</param>
 | 
			
		||||
    /// <param name="right">The second <see cref="Vector2DInt"/>.</param>
 | 
			
		||||
    /// <returns>The <see cref="Vector2DInt"/> containing the minimum components from both input <see cref="Vector2DInt"/>s.</returns>
 | 
			
		||||
    public static Vector2DInt Min(Vector2DInt left, Vector2DInt right) => new((left.X < right.X) ? left.X : right.X, (left.Y < right.Y) ? left.Y : right.Y);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Returns the component-wise maximum of two <see cref="Vector2DInt"/>s.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="left">The first <see cref="Vector2DInt"/>.</param>
 | 
			
		||||
    /// <param name="right">The second <see cref="Vector2DInt"/>.</param>
 | 
			
		||||
    /// <returns>The <see cref="Vector2DInt"/> containing the maximum components from both input <see cref="Vector2DInt"/>s.</returns>
 | 
			
		||||
    public static Vector2DInt Max(Vector2DInt left, Vector2DInt right) => new((left.X > right.X) ? left.X : right.X, (left.Y > right.Y) ? left.Y : right.Y);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Clamps each component of a <see cref="Vector2DInt"/> between the corresponding component of two other <see cref="Vector2DInt"/>s.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="vector">The <see cref="Vector2DInt"/> to clamp.</param>
 | 
			
		||||
    /// <param name="min">The <see cref="Vector2DInt"/> representing the minimum values for each component.</param>
 | 
			
		||||
    /// <param name="max">The <see cref="Vector2DInt"/> representing the maximum values for each component.</param>
 | 
			
		||||
    /// <returns>A <see cref="Vector2DInt"/> with each component clamped between the corresponding components of the min and max <see cref="Vector2DInt"/>s.</returns>
 | 
			
		||||
    public static Vector2DInt Clamp(Vector2DInt vector, Vector2DInt min, Vector2DInt max) => new(Engine.Core.Math.Clamp(vector.X, min.X, max.X), Engine.Core.Math.Clamp(vector.Y, min.Y, max.Y));
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Performs linear interpolation between two <see cref="Vector2DInt"/>s.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="from">The starting <see cref="Vector2DInt"/> (t = 0).</param>
 | 
			
		||||
    /// <param name="to">The ending <see cref="Vector2DInt"/> (t = 1).</param>
 | 
			
		||||
    /// <param name="t">The interpolation parameter.</param>
 | 
			
		||||
    /// <returns>The interpolated <see cref="Vector2DInt"/>.</returns>
 | 
			
		||||
    public static Vector2DInt Lerp(Vector2DInt from, Vector2DInt to, int t) => from + FromTo(from, to) * t;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Calculates the cross product of two <see cref="Vector2DInt"/>s.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="left">The first <see cref="Vector2DInt"/>.</param>
 | 
			
		||||
    /// <param name="right">The second <see cref="Vector2DInt"/>.</param>
 | 
			
		||||
    /// <returns>The cross product of the two <see cref="Vector2DInt"/>s.</returns>
 | 
			
		||||
    public static int Cross(Vector2DInt left, Vector2DInt right) => left.X * right.Y - left.Y * right.X;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Calculates the dot product of two <see cref="Vector2DInt"/>s.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="left">The first <see cref="Vector2DInt"/>.</param>
 | 
			
		||||
    /// <param name="right">The second <see cref="Vector2DInt"/>.</param>
 | 
			
		||||
    /// <returns>The dot product of the two <see cref="Vector2DInt"/>s.</returns>
 | 
			
		||||
    public static int Dot(Vector2DInt left, Vector2DInt right) => left.X * right.X + left.Y * right.Y;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Determines whether the specified object is equal to the current <see cref="Vector2DInt"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="obj">The object to compare with the current <see cref="Vector2DInt"/>.</param>
 | 
			
		||||
    /// <returns><see cref="true"/> if the specified object is equal to the current <see cref="Vector2DInt"/>; otherwise, <see cref="false"/>.</returns>
 | 
			
		||||
    public override bool Equals(object? obj) => obj is Vector2DInt vector2DInt && this == vector2DInt;
 | 
			
		||||
    public bool Equals(Vector2DInt other) => this == other;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Generates a hash code for the <see cref="Vector2DInt"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <returns>A hash code for the <see cref="Vector2DInt"/>.</returns>
 | 
			
		||||
    public override int GetHashCode() => System.HashCode.Combine(X, Y);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Converts the <see cref="Vector2DInt"/> to its string representation.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <returns>A string representation of the <see cref="Vector2DInt"/>.</returns>
 | 
			
		||||
    public override string ToString() => $"{nameof(Vector2DInt)}({X}, {Y})";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Provides extension methods for <see cref="Vector2DInt"/> type.
 | 
			
		||||
/// </summary>
 | 
			
		||||
public static class Vector2DIntExtensions
 | 
			
		||||
{
 | 
			
		||||
    /// <inheritdoc cref="Vector2DInt.Length(Vector2DInt)" />
 | 
			
		||||
    public static float Length(this Vector2DInt vector) => Vector2DInt.Length(vector);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector2DInt.LengthSquared(this vector) => Vector2DInt/>
 | 
			
		||||
    public static float LengthSquared(this Vector2DInt vector) => Vector2DInt.LengthSquared(vector);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector2DInt.Distance(Vector2DInt, Vector2DInt)" />
 | 
			
		||||
    public static float Distance(this Vector2DInt from, Vector2DInt to) => Vector2DInt.Distance(from, to);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector2DInt.Invert(this vector) => Vector2DInt/>
 | 
			
		||||
    public static Vector2DInt Invert(this Vector2DInt vector) => Vector2DInt.Invert(vector);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector2DInt.Add(Vector2DInt, Vector2DInt)" />
 | 
			
		||||
    public static Vector2DInt Add(this Vector2DInt vector, Vector2DInt vectorToAdd) => Vector2DInt.Add(vector, vectorToAdd);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector2DInt.Subtract(Vector2DInt, Vector2DInt)" />
 | 
			
		||||
    public static Vector2DInt Subtract(this Vector2DInt vector, Vector2DInt vectorToSubtract) => Vector2DInt.Subtract(vector, vectorToSubtract);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector2DInt.Multiply(Vector2DInt, int)" />
 | 
			
		||||
    public static Vector2DInt Multiply(this Vector2DInt vector, int value) => Vector2DInt.Multiply(vector, value);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector2DInt.Divide(Vector2DInt, int)" />
 | 
			
		||||
    public static Vector2DInt Divide(this Vector2DInt vector, int value) => Vector2DInt.Divide(vector, value);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector2DInt.Abs(Vector2DInt)" />
 | 
			
		||||
    public static Vector2DInt Abs(this Vector2DInt vector) => Vector2DInt.Abs(vector);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector2DInt.FromTo(Vector2DInt, Vector2DInt)" />
 | 
			
		||||
    public static Vector2DInt FromTo(this Vector2DInt from, Vector2DInt to) => Vector2DInt.FromTo(from, to);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector2DInt.Scale(Vector2DInt, Vector2DInt)" />
 | 
			
		||||
    public static Vector2DInt Scale(this Vector2DInt vector, Vector2DInt scale) => Vector2DInt.Scale(vector, scale);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector2DInt.Perpendicular(Vector2DInt)" />
 | 
			
		||||
    public static Vector2DInt Perpendicular(this Vector2DInt vector) => Vector2DInt.Perpendicular(vector);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector2DInt.Min(Vector2DInt, Vector2DInt)" />
 | 
			
		||||
    public static Vector2DInt Min(this Vector2DInt left, Vector2DInt right) => Vector2DInt.Min(left, right);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector2DInt.Max(Vector2DInt, Vector2DInt)" />
 | 
			
		||||
    public static Vector2DInt Max(this Vector2DInt left, Vector2DInt right) => Vector2DInt.Max(left, right);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector2DInt.Clamp(Vector2DInt, Vector2DInt,Vector2DInt)" />
 | 
			
		||||
    public static Vector2DInt Clamp(this Vector2DInt vector, Vector2DInt min, Vector2DInt max) => Vector2DInt.Clamp(vector, min, max);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector2DInt.Lerp(Vector2DInt, Vector2DInt," />
 | 
			
		||||
    public static Vector2DInt Lerp(this Vector2DInt from, Vector2DInt to, int t) => Vector2DInt.Lerp(from, to, t);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector2DInt.Cross(Vector2DInt, Vector2DInt)" />
 | 
			
		||||
    public static int Cross(this Vector2DInt left, Vector2DInt right) => Vector2DInt.Cross(left, right);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector2D.Angle(Vector2D, Vector2D)" />
 | 
			
		||||
    public static float AngleBetween(this Vector2D left, Vector2D right) => Vector2D.Angle(left, right);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector2DInt.Dot(Vector2DInt, Vector2DInt)" />
 | 
			
		||||
    public static int Dot(this Vector2DInt left, Vector2DInt right) => Vector2DInt.Dot(left, right);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,6 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents a three-dimensional vector.
 | 
			
		||||
@@ -10,7 +12,7 @@ namespace Syntriax.Engine.Core;
 | 
			
		||||
/// Initializes a new instance of the <see cref="Vector3D"/> struct with the specified positions.
 | 
			
		||||
/// </remarks>
 | 
			
		||||
[System.Diagnostics.DebuggerDisplay("{ToString(),nq}, Length: {Magnitude}, LengthSquared: {MagnitudeSquared}, Normalized: {Normalized.ToString(),nq}")]
 | 
			
		||||
public readonly struct Vector3D(float x, float y, float z)
 | 
			
		||||
public readonly struct Vector3D(float x, float y, float z) : IEquatable<Vector3D>
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The X coordinate of the <see cref="Vector3D"/>.
 | 
			
		||||
@@ -92,6 +94,7 @@ public readonly struct Vector3D(float x, float y, float z)
 | 
			
		||||
 | 
			
		||||
    public static implicit operator System.Numerics.Vector3(Vector3D vector) => new(vector.X, vector.Y, vector.Z);
 | 
			
		||||
    public static implicit operator Vector3D(System.Numerics.Vector3 vector) => new(vector.X, vector.Y, vector.Z);
 | 
			
		||||
    public static implicit operator Vector3D(Vector3DInt vector) => new(vector.X, vector.Y, vector.Z);
 | 
			
		||||
    public static implicit operator Vector3D(Vector2D vector) => new(vector.X, vector.Y, 0f);
 | 
			
		||||
    public static implicit operator Vector3D(System.Numerics.Vector2 vector) => new(vector.X, vector.Y, 0f);
 | 
			
		||||
 | 
			
		||||
@@ -277,6 +280,7 @@ public readonly struct Vector3D(float x, float y, float z)
 | 
			
		||||
    /// <param name="obj">The object to compare with the current <see cref="Vector3D"/>.</param>
 | 
			
		||||
    /// <returns><see cref="true"/> if the specified object is equal to the current <see cref="Vector3D"/>; otherwise, <see cref="false"/>.</returns>
 | 
			
		||||
    public override bool Equals(object? obj) => obj is Vector3D vector3D && this == vector3D;
 | 
			
		||||
    public bool Equals(Vector3D other) => this == other;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Generates a hash code for the <see cref="Vector3D"/>.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										314
									
								
								Engine.Core/Primitives/Vector3DInt.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										314
									
								
								Engine.Core/Primitives/Vector3DInt.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,314 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents a three-dimensional integer vector.
 | 
			
		||||
/// </summary>
 | 
			
		||||
/// <param name="x">X position of the <see cref="Vector3DInt"/>.</param>
 | 
			
		||||
/// <param name="y">Y position of the <see cref="Vector3DInt"/>.</param>
 | 
			
		||||
/// <param name="z">Z position of the <see cref="Vector3DInt"/>.</param>
 | 
			
		||||
/// <remarks>
 | 
			
		||||
/// Initializes a new instance of the <see cref="Vector3DInt"/> struct with the specified positions.
 | 
			
		||||
/// </remarks>
 | 
			
		||||
[System.Diagnostics.DebuggerDisplay("{ToString(),nq}")]
 | 
			
		||||
public readonly struct Vector3DInt(int x, int y, int z) : IEquatable<Vector3DInt>
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The X coordinate of the <see cref="Vector3DInt"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public readonly int X = x;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The Y coordinate of the <see cref="Vector3DInt"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public readonly int Y = y;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The Z coordinate of the <see cref="Vector3DInt"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public readonly int Z = z;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The magnitude (length) of the <see cref="Vector3DInt"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public float Magnitude => Length(this);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The squared magnitude (length) of the <see cref="Vector3DInt"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public float MagnitudeSquared => LengthSquared(this);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Represents the unit <see cref="Vector3DInt"/> pointing upwards.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public readonly static Vector3DInt Up = new(0, 1, 0);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Represents the unit <see cref="Vector3DInt"/> pointing downwards.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public readonly static Vector3DInt Down = new(0, -1, 0);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Represents the unit <see cref="Vector3DInt"/> pointing leftwards.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public readonly static Vector3DInt Left = new(-1, 0, 0);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Represents the unit <see cref="Vector3DInt"/> pointing rightwards.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public readonly static Vector3DInt Right = new(1, 0, 0);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Represents the unit <see cref="Vector3DInt"/> pointing forwards.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public readonly static Vector3DInt Forward = new(0, 0, 1);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Represents the unit <see cref="Vector3DInt"/> pointing backwards.
 | 
			
		||||
    public readonly static Vector3DInt Backward = new(0, 0, -1);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Represents the zero <see cref="Vector3DInt"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public readonly static Vector3DInt Zero = new(0, 0, 0);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Represents the <see cref="Vector3DInt"/> with both components equal to 1.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public readonly static Vector3DInt One = new(1, 1, 1);
 | 
			
		||||
 | 
			
		||||
    public static Vector3DInt operator -(Vector3DInt vector) => new(0 - vector.X, 0 - vector.Y, 0 - vector.Z);
 | 
			
		||||
    public static Vector3DInt operator +(Vector3DInt left, Vector3DInt right) => new(left.X + right.X, left.Y + right.Y, left.Z + right.Z);
 | 
			
		||||
    public static Vector3DInt operator -(Vector3DInt left, Vector3DInt right) => new(left.X - right.X, left.Y - right.Y, left.Z - right.Z);
 | 
			
		||||
    public static Vector3DInt operator *(Vector3DInt vector, int value) => new(vector.X * value, vector.Y * value, vector.Z * value);
 | 
			
		||||
    public static Vector3DInt operator *(int value, Vector3DInt vector) => new(vector.X * value, vector.Y * value, vector.Z * value);
 | 
			
		||||
    public static Vector3DInt operator /(Vector3DInt vector, int value) => new(vector.X / value, vector.Y / value, vector.Z / value);
 | 
			
		||||
    public static bool operator ==(Vector3DInt left, Vector3DInt right) => left.X == right.X && left.Y == right.Y && left.Z == right.Z;
 | 
			
		||||
    public static bool operator !=(Vector3DInt left, Vector3DInt right) => left.X != right.X || left.Y != right.Y || left.Z != right.Z;
 | 
			
		||||
 | 
			
		||||
    public static implicit operator Vector3DInt(Vector3D vector) => new(vector.X.RoundToInt(), vector.Y.RoundToInt(), vector.Z.RoundToInt());
 | 
			
		||||
    public static implicit operator Vector3DInt(Vector2DInt vector) => new(vector.X, vector.Y, 0);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Calculates the length of the <see cref="Vector3DInt"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="vector">The <see cref="Vector3DInt"/>.</param>
 | 
			
		||||
    /// <returns>The length of the <see cref="Vector3DInt"/>.</returns>
 | 
			
		||||
    public static float Length(Vector3DInt vector) => Math.Sqrt(LengthSquared(vector));
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Calculates the squared length of the <see cref="Vector3DInt"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="vector">The <see cref="Vector3DInt"/>.</param>
 | 
			
		||||
    /// <returns>The squared length of the <see cref="Vector3DInt"/>.</returns>
 | 
			
		||||
    public static float LengthSquared(Vector3DInt vector) => vector.X * vector.X + vector.Y * vector.Y + vector.Z * vector.Z;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Calculates the distance between two <see cref="Vector3DInt"/>s.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="from">The start <see cref="Vector3DInt"/>.</param>
 | 
			
		||||
    /// <param name="to">The end <see cref="Vector3DInt"/>.</param>
 | 
			
		||||
    /// <returns>The distance between the two <see cref="Vector3DInt"/>s.</returns>
 | 
			
		||||
    public static float Distance(Vector3DInt from, Vector3DInt to) => Length(FromTo(from, to));
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Inverts the direction of the <see cref="Vector3DInt"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="vector">The <see cref="Vector3DInt"/>.</param>
 | 
			
		||||
    /// <returns>The inverted <see cref="Vector3DInt"/>.</returns>
 | 
			
		||||
    public static Vector3DInt Invert(Vector3DInt vector) => -vector;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Adds two <see cref="Vector3DInt"/>s.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="left">The first <see cref="Vector3DInt"/>.</param>
 | 
			
		||||
    /// <param name="right">The second <see cref="Vector3DInt"/>.</param>
 | 
			
		||||
    /// <returns>The sum of the two <see cref="Vector3DInt"/>s.</returns>
 | 
			
		||||
    public static Vector3DInt Add(Vector3DInt left, Vector3DInt right) => left + right;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Subtracts one <see cref="Vector3DInt"/> from another.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="left">The <see cref="Vector3DInt"/> to subtract from.</param>
 | 
			
		||||
    /// <param name="right">The <see cref="Vector3DInt"/> to subtract.</param>
 | 
			
		||||
    /// <returns>The result of subtracting the second <see cref="Vector3DInt"/> from the first.</returns>
 | 
			
		||||
    public static Vector3DInt Subtract(Vector3DInt left, Vector3DInt right) => left - right;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Multiplies a <see cref="Vector3DInt"/> by a scalar value.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="vector">The <see cref="Vector3DInt"/>.</param>
 | 
			
		||||
    /// <param name="value">The scalar value.</param>
 | 
			
		||||
    /// <returns>The result of multiplying the <see cref="Vector3DInt"/> by the scalar value.</returns>
 | 
			
		||||
    public static Vector3DInt Multiply(Vector3DInt vector, int value) => vector * value;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Divides a <see cref="Vector3DInt"/> by a scalar value.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="vector">The <see cref="Vector3DInt"/>.</param>
 | 
			
		||||
    /// <param name="value">The scalar value.</param>
 | 
			
		||||
    /// <returns>The result of dividing the <see cref="Vector3DInt"/> by the scalar value.</returns>
 | 
			
		||||
    public static Vector3DInt Divide(Vector3DInt vector, int value) => vector / value;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Calculates the absolute value of each component of the vector.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="vector">The <see cref="Vector3DInt"/>.</param>
 | 
			
		||||
    /// <returns>The <see cref="Vector3DInt"/> with each component's absolute value.</returns>
 | 
			
		||||
    public static Vector3DInt Abs(Vector3DInt vector) => new(Math.Abs(vector.X), Math.Abs(vector.Y), Math.Abs(vector.Z));
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Calculates the <see cref="Vector3DInt"/> from one point to another.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="from">The starting point.</param>
 | 
			
		||||
    /// <param name="to">The ending point.</param>
 | 
			
		||||
    /// <returns>The <see cref="Vector3DInt"/> from the starting point to the ending point.</returns>
 | 
			
		||||
    public static Vector3DInt FromTo(Vector3DInt from, Vector3DInt to) => to - from;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Scales a <see cref="Vector3DInt"/> by another <see cref="Vector3DInt"/> component-wise.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="vector">The <see cref="Vector3DInt"/> to scale.</param>
 | 
			
		||||
    /// <param name="scale">The <see cref="Vector3DInt"/> containing the scaling factors for each component.</param>
 | 
			
		||||
    /// <returns>The scaled <see cref="Vector3DInt"/>.</returns>
 | 
			
		||||
    public static Vector3DInt Scale(Vector3DInt vector, Vector3DInt scale) => new(vector.X * scale.X, vector.Y * scale.Y, vector.Z * scale.Z);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Returns the component-wise minimum of two <see cref="Vector3DInt"/>s.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="left">The first <see cref="Vector3DInt"/>.</param>
 | 
			
		||||
    /// <param name="right">The second <see cref="Vector3DInt"/>.</param>
 | 
			
		||||
    /// <returns>The <see cref="Vector3DInt"/> containing the minimum components from both input <see cref="Vector3DInt"/>s.</returns>
 | 
			
		||||
    public static Vector3DInt Min(Vector3DInt left, Vector3DInt right) => new((left.X < right.X) ? left.X : right.X, (left.Y < right.Y) ? left.Y : right.Y, (left.Z < right.Z) ? left.Z : right.Z);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Returns the component-wise maximum of two <see cref="Vector3DInt"/>s.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="left">The first <see cref="Vector3DInt"/>.</param>
 | 
			
		||||
    /// <param name="right">The second <see cref="Vector3DInt"/>.</param>
 | 
			
		||||
    /// <returns>The <see cref="Vector3DInt"/> containing the maximum components from both input <see cref="Vector3DInt"/>s.</returns>
 | 
			
		||||
    public static Vector3DInt Max(Vector3DInt left, Vector3DInt right) => new((left.X > right.X) ? left.X : right.X, (left.Y > right.Y) ? left.Y : right.Y, (left.Z > right.Z) ? left.Z : right.Z);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Clamps each component of a <see cref="Vector3DInt"/> between the corresponding component of two other <see cref="Vector3DInt"/>s.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="vector">The <see cref="Vector3DInt"/> to clamp.</param>
 | 
			
		||||
    /// <param name="min">The <see cref="Vector3DInt"/> representing the minimum values for each component.</param>
 | 
			
		||||
    /// <param name="max">The <see cref="Vector3DInt"/> representing the maximum values for each component.</param>
 | 
			
		||||
    /// <returns>A <see cref="Vector3DInt"/> with each component clamped between the corresponding components of the min and max <see cref="Vector3DInt"/>s.</returns>
 | 
			
		||||
    public static Vector3DInt Clamp(Vector3DInt vector, Vector3DInt min, Vector3DInt max) => new(Math.Clamp(vector.X, min.X, max.X), Math.Clamp(vector.Y, min.Y, max.Y), Math.Clamp(vector.Z, min.Z, max.Z));
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Performs linear interpolation between two <see cref="Vector3DInt"/>s.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="from">The starting <see cref="Vector3DInt"/> (t = 0).</param>
 | 
			
		||||
    /// <param name="to">The ending <see cref="Vector3DInt"/> (t = 1).</param>
 | 
			
		||||
    /// <param name="t">The interpolation parameter.</param>
 | 
			
		||||
    /// <returns>The interpolated <see cref="Vector3DInt"/>.</returns>
 | 
			
		||||
    public static Vector3DInt Lerp(Vector3DInt from, Vector3DInt to, int t) => from + FromTo(from, to) * t;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Calculates the cross product of two <see cref="Vector3DInt"/>s.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="left">The first <see cref="Vector3DInt"/>.</param>
 | 
			
		||||
    /// <param name="right">The second <see cref="Vector3DInt"/>.</param>
 | 
			
		||||
    /// <returns>The cross product of the two <see cref="Vector3DInt"/>s.</returns>
 | 
			
		||||
    public static Vector3DInt Cross(Vector3DInt left, Vector3DInt right) => new(left.Y * right.Z - left.Z * right.Y, left.Z * right.X - left.X * right.Z, left.X * right.Y - left.Y * right.X);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Calculates the angle between two <see cref="Vector3DInt"/>s.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="left">The first <see cref="Vector3DInt"/>.</param>
 | 
			
		||||
    /// <param name="right">The second <see cref="Vector3DInt"/>.</param>
 | 
			
		||||
    /// <returns>The angle between the two <see cref="Vector3DInt"/>s in radians.</returns>
 | 
			
		||||
    public static float Angle(Vector3DInt left, Vector3DInt right) => Math.Acos(Dot(left, right) / (Length(left) * Length(right)));
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Calculates the dot product of two <see cref="Vector3DInt"/>s.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="left">The first <see cref="Vector3DInt"/>.</param>
 | 
			
		||||
    /// <param name="right">The second <see cref="Vector3DInt"/>.</param>
 | 
			
		||||
    /// <returns>The dot product of the two <see cref="Vector3DInt"/>s.</returns>
 | 
			
		||||
    public static int Dot(Vector3DInt left, Vector3DInt right) => left.X * right.X + left.Y * right.Y + left.Z * right.Z;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Determines whether the specified object is equal to the current <see cref="Vector3DInt"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="obj">The object to compare with the current <see cref="Vector3DInt"/>.</param>
 | 
			
		||||
    /// <returns><see cref="true"/> if the specified object is equal to the current <see cref="Vector3DInt"/>; otherwise, <see cref="false"/>.</returns>
 | 
			
		||||
    public override bool Equals(object? obj) => obj is Vector3DInt vector3D && this == vector3D;
 | 
			
		||||
    public bool Equals(Vector3DInt other) => this == other;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Generates a hash code for the <see cref="Vector3DInt"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <returns>A hash code for the <see cref="Vector3DInt"/>.</returns>
 | 
			
		||||
    public override int GetHashCode() => System.HashCode.Combine(X, Y, Z);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Converts the <see cref="Vector3DInt"/> to its string representation.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <returns>A string representation of the <see cref="Vector3DInt"/>.</returns>
 | 
			
		||||
    public override string ToString() => $"{nameof(Vector3DInt)}({X}, {Y}, {Z})";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Provides extension methods for <see cref="Vector3DInt"/> type.
 | 
			
		||||
/// </summary>
 | 
			
		||||
public static class Vector3DIntExtensions
 | 
			
		||||
{
 | 
			
		||||
    /// <inheritdoc cref="Vector3DInt.Length(Vector3DInt)" />
 | 
			
		||||
    public static float Length(this Vector3DInt vector) => Vector3DInt.Length(vector);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector3DInt.LengthSquared(Vector3DInt)" />
 | 
			
		||||
    public static float LengthSquared(this Vector3DInt vector) => Vector3DInt.LengthSquared(vector);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector3DInt.Distance(Vector3DInt, Vector3DInt)" />
 | 
			
		||||
    public static float Distance(this Vector3DInt from, Vector3DInt to) => Vector3DInt.Distance(from, to);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector3DInt.Invert(Vector3DInt)" />
 | 
			
		||||
    public static Vector3DInt Invert(this Vector3DInt vector) => Vector3DInt.Invert(vector);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector3DInt.Add(Vector3DInt, Vector3DInt)" />
 | 
			
		||||
    public static Vector3DInt Add(this Vector3DInt vector, Vector3DInt vectorToAdd) => Vector3DInt.Add(vector, vectorToAdd);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector3DInt.Subtract(Vector3DInt, Vector3DInt)" />
 | 
			
		||||
    public static Vector3DInt Subtract(this Vector3DInt vector, Vector3DInt vectorToSubtract) => Vector3DInt.Subtract(vector, vectorToSubtract);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector3DInt.Multiply(Vector3DInt, int)" />
 | 
			
		||||
    public static Vector3DInt Multiply(this Vector3DInt vector, int value) => Vector3DInt.Multiply(vector, value);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector3DInt.Divide(Vector3DInt, int)" />
 | 
			
		||||
    public static Vector3DInt Divide(this Vector3DInt vector, int value) => Vector3DInt.Divide(vector, value);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector3DInt.Abs(Vector3DInt)" />
 | 
			
		||||
    public static Vector3DInt Abs(this Vector3DInt vector) => Vector3DInt.Abs(vector);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector3DInt.FromTo(Vector3DInt, Vector3DInt)" />
 | 
			
		||||
    public static Vector3DInt FromTo(this Vector3DInt from, Vector3DInt to) => Vector3DInt.FromTo(from, to);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector3DInt.Scale(Vector3DInt, Vector3DInt)" />
 | 
			
		||||
    public static Vector3DInt Scale(this Vector3DInt vector, Vector3DInt scale) => Vector3DInt.Scale(vector, scale);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector3DInt.Min(Vector3DInt, Vector3DInt)" />
 | 
			
		||||
    public static Vector3DInt Min(this Vector3DInt left, Vector3DInt right) => Vector3DInt.Min(left, right);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector3DInt.Max(Vector3DInt, Vector3DInt)" />
 | 
			
		||||
    public static Vector3DInt Max(this Vector3DInt left, Vector3DInt right) => Vector3DInt.Max(left, right);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector3DInt.Clamp(Vector3DInt, Vector3DInt, Vector3DInt)" />
 | 
			
		||||
    public static Vector3DInt Clamp(this Vector3DInt vector, Vector3DInt min, Vector3DInt max) => Vector3DInt.Clamp(vector, min, max);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector3DInt.Lerp(Vector3DInt, Vector3DInt, int)" />
 | 
			
		||||
    public static Vector3DInt Lerp(this Vector3DInt from, Vector3DInt to, int t) => Vector3DInt.Lerp(from, to, t);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector3DInt.Cross(Vector3DInt, Vector3DInt)" />
 | 
			
		||||
    public static Vector3DInt Cross(this Vector3DInt left, Vector3DInt right) => Vector3DInt.Cross(left, right);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector3DInt.Angle(Vector3DInt, Vector3DInt)" />
 | 
			
		||||
    public static float AngleBetween(this Vector3DInt left, Vector3DInt right) => Vector3DInt.Angle(left, right);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Vector3DInt.Dot(Vector3DInt, Vector3DInt)" />
 | 
			
		||||
    public static int Dot(this Vector3DInt left, Vector3DInt right) => Vector3DInt.Dot(left, right);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Serialization;
 | 
			
		||||
namespace Engine.Core.Serialization;
 | 
			
		||||
 | 
			
		||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Class)]
 | 
			
		||||
public class IgnoreSerializationAttribute : Attribute;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Serialization;
 | 
			
		||||
namespace Engine.Core.Serialization;
 | 
			
		||||
 | 
			
		||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
 | 
			
		||||
public class SerializeAllAttribute : Attribute;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Serialization;
 | 
			
		||||
namespace Engine.Core.Serialization;
 | 
			
		||||
 | 
			
		||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
 | 
			
		||||
public class SerializeAttribute : Attribute;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,3 @@
 | 
			
		||||
namespace Syntriax.Engine.Core.Serialization;
 | 
			
		||||
namespace Engine.Core.Serialization;
 | 
			
		||||
 | 
			
		||||
public record class EntityReference(string? Id = null);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Serialization;
 | 
			
		||||
namespace Engine.Core.Serialization;
 | 
			
		||||
 | 
			
		||||
public class EntityRegistry
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Serialization;
 | 
			
		||||
namespace Engine.Core.Serialization;
 | 
			
		||||
 | 
			
		||||
public interface ISerializer
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user