Compare commits
	
		
			69 Commits
		
	
	
		
			6e5b805803
			...
			0bf38234c6
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 0bf38234c6 | |||
| ed6969c16a | |||
| b0b421151f | |||
| 41c5def097 | |||
| fbbdfb07fa | |||
| bf283d804c | |||
| 063ea08707 | |||
| fd11a94ddf | |||
| be2295b92d | |||
| a93e55619c | |||
| 48ae24af47 | |||
| 1366a417f1 | |||
| 4bfe98852c | |||
| 98edbe1af5 | |||
| 3725a3b0fd | |||
| f43ab36742 | |||
| c7aafd85bc | |||
| 5de08b8fe4 | |||
| 16e4077d40 | |||
| fc3c1ed1f9 | |||
| b100b5c2fe | |||
| 5e28ba8814 | |||
| 4c235e3230 | |||
| 131203d578 | |||
| bd5eb432b7 | |||
| d2ca85568f | |||
| 4c41870732 | |||
| f77afa3632 | |||
| eb61598489 | |||
| efe51b491d | |||
| fa3a4d1e0d | |||
| 6e7a0993f5 | |||
| d70bee2c6b | |||
| 5812f43117 | |||
| d102c5471d | |||
| fb363970fc | |||
| 791349686b | |||
| 3a0942ff46 | |||
| b002dd469a | |||
| f92f36442c | |||
| bb934b59f3 | |||
| c704173183 | |||
| c3876add1e | |||
| 35a75d993b | |||
| 2637f99456 | |||
| 9581f5aa54 | |||
| 82cc25a9ef | |||
| 336e7e16e7 | |||
| a3a8fb4e84 | |||
| 35f6c3850e | |||
| f51d5f342e | |||
| 9c129cefe2 | |||
| a254bb721b | |||
| 5fa7420c04 | |||
| 5bcc256777 | |||
| 680d718957 | |||
| 20bc6a1adb | |||
| eb454a471c | |||
| c205e710bc | |||
| cddb30c631 | |||
| 29f6c83bf0 | |||
| c20f210b29 | |||
| 1ea1844677 | |||
| 5b2c13f8bf | |||
| c39ee44442 | |||
| 4623b4861a | |||
| 0a868b82e5 | |||
| d92d16cfad | |||
| 0184d1758c | 
							
								
								
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
[submodule "Engine.Serializers/YamlDotNet"]
 | 
			
		||||
	path = Engine.Serializers/YamlDotNet
 | 
			
		||||
	url = git@github.com:Syntriax/YamlDotNet.git
 | 
			
		||||
							
								
								
									
										2
									
								
								Engine.Core/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								Engine.Core/.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -482,3 +482,5 @@ $RECYCLE.BIN/
 | 
			
		||||
 | 
			
		||||
# Vim temporary swap files
 | 
			
		||||
*.swp
 | 
			
		||||
 | 
			
		||||
!Debug
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,7 @@ namespace Syntriax.Engine.Core;
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents a controller for managing <see cref="IBehaviour"/>s and notify them accordingly about the engine's updates. Connected to an <see cref="IUniverseObject"/>.
 | 
			
		||||
/// </summary>
 | 
			
		||||
public interface IBehaviourController : IInitializable, IHasUniverseObject, IEnumerable<IBehaviour>
 | 
			
		||||
public interface IBehaviourController : IEntity, IHasUniverseObject, IEnumerable<IBehaviour>
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Event triggered before the update of <see cref="IBehaviour"/>s.
 | 
			
		||||
 
 | 
			
		||||
@@ -53,7 +53,7 @@ public abstract class Behaviour : BehaviourBase
 | 
			
		||||
    protected virtual void OnPreUpdate() { }
 | 
			
		||||
    protected virtual void PreUpdate(IBehaviourController _)
 | 
			
		||||
    {
 | 
			
		||||
        Debug.AssertHelpers.AssertInitialized(this);
 | 
			
		||||
        Debug.Assert.AssertInitialized(this);
 | 
			
		||||
 | 
			
		||||
        OnPreUpdatePreActiveCheck();
 | 
			
		||||
 | 
			
		||||
@@ -77,7 +77,7 @@ public abstract class Behaviour : BehaviourBase
 | 
			
		||||
    protected virtual void OnUpdate() { }
 | 
			
		||||
    protected virtual void Update(IBehaviourController _)
 | 
			
		||||
    {
 | 
			
		||||
        Debug.AssertHelpers.AssertInitialized(this);
 | 
			
		||||
        Debug.Assert.AssertInitialized(this);
 | 
			
		||||
 | 
			
		||||
        OnUpdatePreActiveCheck();
 | 
			
		||||
 | 
			
		||||
@@ -91,7 +91,7 @@ public abstract class Behaviour : BehaviourBase
 | 
			
		||||
    protected virtual void OnPreDraw() { }
 | 
			
		||||
    protected virtual void PreDraw(IBehaviourController _)
 | 
			
		||||
    {
 | 
			
		||||
        Debug.AssertHelpers.AssertInitialized(this);
 | 
			
		||||
        Debug.Assert.AssertInitialized(this);
 | 
			
		||||
 | 
			
		||||
        OnPreDrawPreActiveCheck();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -66,8 +66,8 @@ public abstract class BehaviourBase : BaseEntity, IBehaviour
 | 
			
		||||
 | 
			
		||||
    protected override void InitializeInternal()
 | 
			
		||||
    {
 | 
			
		||||
        Debug.AssertHelpers.AssertBehaviourControllerAssigned(this);
 | 
			
		||||
        Debug.AssertHelpers.AssertStateEnableAssigned(this);
 | 
			
		||||
        Debug.Assert.AssertBehaviourControllerAssigned(this);
 | 
			
		||||
        Debug.Assert.AssertStateEnableAssigned(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void OnStateEnabledChanged(IStateEnable sender, bool previousState) => UpdateActive();
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@ using System.Linq;
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
[System.Diagnostics.DebuggerDisplay("Behaviour Count: {behaviours.Count}")]
 | 
			
		||||
public class BehaviourController : IBehaviourController
 | 
			
		||||
public class BehaviourController : BaseEntity, IBehaviourController
 | 
			
		||||
{
 | 
			
		||||
    public event IBehaviourController.PreUpdateEventHandler? OnPreUpdate = null;
 | 
			
		||||
    public event IBehaviourController.UpdateEventHandler? OnUpdate = null;
 | 
			
		||||
@@ -16,42 +16,20 @@ public class BehaviourController : IBehaviourController
 | 
			
		||||
    public event IBehaviourController.BehaviourRemovedEventHandler? OnBehaviourRemoved = null;
 | 
			
		||||
    public event IHasUniverseObject.UniverseObjectAssignedEventHandler? OnUniverseObjectAssigned = null;
 | 
			
		||||
 | 
			
		||||
    public event IInitializable.InitializedEventHandler? OnInitialized = null;
 | 
			
		||||
    public event IInitializable.FinalizedEventHandler? OnFinalized = null;
 | 
			
		||||
 | 
			
		||||
    public event IAssignable.UnassignEventHandler? OnUnassigned = null;
 | 
			
		||||
 | 
			
		||||
    private readonly IList<IBehaviour> behaviours = new List<IBehaviour>(Constants.BEHAVIOURS_SIZE_INITIAL);
 | 
			
		||||
 | 
			
		||||
    private IUniverseObject _universeObject = null!;
 | 
			
		||||
    private bool _initialized = false;
 | 
			
		||||
 | 
			
		||||
    public IUniverseObject UniverseObject => _universeObject;
 | 
			
		||||
 | 
			
		||||
    public bool IsInitialized
 | 
			
		||||
    {
 | 
			
		||||
        get => _initialized;
 | 
			
		||||
        private set
 | 
			
		||||
        {
 | 
			
		||||
            if (value == _initialized)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            _initialized = value;
 | 
			
		||||
            if (value)
 | 
			
		||||
                OnInitialized?.InvokeSafe(this);
 | 
			
		||||
            else
 | 
			
		||||
                OnFinalized?.InvokeSafe(this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public T AddBehaviour<T>(T behaviour) where T : class, IBehaviour
 | 
			
		||||
    {
 | 
			
		||||
        InsertBehaviourByPriority(behaviour);
 | 
			
		||||
 | 
			
		||||
        behaviour.Assign(this);
 | 
			
		||||
        behaviour.Assign(Factory.StateEnableFactory.Instantiate(behaviour));
 | 
			
		||||
 | 
			
		||||
        behaviour.Initialize();
 | 
			
		||||
        if (IsInitialized)
 | 
			
		||||
            behaviour.Initialize();
 | 
			
		||||
        behaviour.OnPriorityChanged += OnPriorityChange;
 | 
			
		||||
        OnBehaviourAdded?.InvokeSafe(this, behaviour);
 | 
			
		||||
        return behaviour;
 | 
			
		||||
@@ -133,45 +111,25 @@ public class BehaviourController : IBehaviourController
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool Initialize()
 | 
			
		||||
    protected override void InitializeInternal()
 | 
			
		||||
    {
 | 
			
		||||
        if (IsInitialized)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        Debug.AssertHelpers.AssertUniverseObjectAssigned(this);
 | 
			
		||||
        Debug.Assert.AssertUniverseObjectAssigned(this);
 | 
			
		||||
 | 
			
		||||
        foreach (IBehaviour behaviour in behaviours)
 | 
			
		||||
            behaviour.Initialize();
 | 
			
		||||
 | 
			
		||||
        IsInitialized = true;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool Finalize()
 | 
			
		||||
    protected override void FinalizeInternal()
 | 
			
		||||
    {
 | 
			
		||||
        if (!IsInitialized)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        foreach (IBehaviour behaviour in behaviours)
 | 
			
		||||
            behaviour.Finalize();
 | 
			
		||||
 | 
			
		||||
        IsInitialized = false;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool Unassign()
 | 
			
		||||
    {
 | 
			
		||||
        if (IsInitialized)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        _universeObject = null!;
 | 
			
		||||
        OnUnassigned?.InvokeSafe(this);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void Update()
 | 
			
		||||
    {
 | 
			
		||||
        if (!UniverseObject.StateEnable.Enabled)
 | 
			
		||||
        Debug.Assert.AssertInitialized(this);
 | 
			
		||||
 | 
			
		||||
        if (!UniverseObject.StateEnable.Enabled || !StateEnable.Enabled)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        OnPreUpdate?.InvokeSafe(this);
 | 
			
		||||
@@ -180,7 +138,9 @@ public class BehaviourController : IBehaviourController
 | 
			
		||||
 | 
			
		||||
    public void UpdatePreDraw()
 | 
			
		||||
    {
 | 
			
		||||
        if (!UniverseObject.StateEnable.Enabled)
 | 
			
		||||
        Debug.Assert.AssertInitialized(this);
 | 
			
		||||
 | 
			
		||||
        if (!UniverseObject.StateEnable.Enabled || !StateEnable.Enabled)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        OnPreDraw?.InvokeSafe(this);
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@ using System.Runtime.CompilerServices;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Debug;
 | 
			
		||||
 | 
			
		||||
public class AssertHelpers
 | 
			
		||||
public static class Assert
 | 
			
		||||
{
 | 
			
		||||
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 | 
			
		||||
    public static void AssertInitialized(IInitializable initializable)
 | 
			
		||||
							
								
								
									
										8
									
								
								Engine.Core/Debug/ConsoleLogger.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								Engine.Core/Debug/ConsoleLogger.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Debug;
 | 
			
		||||
 | 
			
		||||
public class ConsoleLogger : LoggerBase
 | 
			
		||||
{
 | 
			
		||||
    protected override void Write(string message) => Console.WriteLine(message);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										20
									
								
								Engine.Core/Debug/FileLogger.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								Engine.Core/Debug/FileLogger.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.IO;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Debug;
 | 
			
		||||
 | 
			
		||||
public class FileLogger : LoggerBase
 | 
			
		||||
{
 | 
			
		||||
    public readonly string FilePath;
 | 
			
		||||
 | 
			
		||||
    public FileLogger(string filePath)
 | 
			
		||||
    {
 | 
			
		||||
        FilePath = filePath;
 | 
			
		||||
        File.Open(filePath, FileMode.Create).Close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void Write(string message)
 | 
			
		||||
    {
 | 
			
		||||
        File.AppendAllTextAsync(FilePath, $"{message}{Environment.NewLine}");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15
									
								
								Engine.Core/Debug/ILogger.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								Engine.Core/Debug/ILogger.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
namespace Syntriax.Engine.Core.Debug;
 | 
			
		||||
 | 
			
		||||
public interface ILogger
 | 
			
		||||
{
 | 
			
		||||
    Level FilterLevel { get; set; }
 | 
			
		||||
 | 
			
		||||
    void Log(string message, Level level = Level.Info, bool force = false);
 | 
			
		||||
 | 
			
		||||
    enum Level
 | 
			
		||||
    {
 | 
			
		||||
        Info,
 | 
			
		||||
        Warning,
 | 
			
		||||
        Error,
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										20
									
								
								Engine.Core/Debug/LoggerBase.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								Engine.Core/Debug/LoggerBase.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Debug;
 | 
			
		||||
 | 
			
		||||
public abstract class LoggerBase : ILogger
 | 
			
		||||
{
 | 
			
		||||
    public ILogger.Level FilterLevel { get; set; } = ILogger.Level.Info;
 | 
			
		||||
 | 
			
		||||
    public void Log(string message, ILogger.Level level = ILogger.Level.Info, bool force = false)
 | 
			
		||||
    {
 | 
			
		||||
        if (!force && level < FilterLevel)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        string timestamp = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss tt");
 | 
			
		||||
 | 
			
		||||
        Write($"[{timestamp}] [{level}] \t{message}");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected abstract void Write(string message);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										28
									
								
								Engine.Core/Debug/LoggerExtensions.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								Engine.Core/Debug/LoggerExtensions.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Debug;
 | 
			
		||||
 | 
			
		||||
public static class LoggerExtensions
 | 
			
		||||
{
 | 
			
		||||
    public static void Log<T>(this ILogger logger, T caller, string message, ILogger.Level level = ILogger.Level.Info, bool force = false)
 | 
			
		||||
    {
 | 
			
		||||
        string body = $"{caller?.GetType().Name ?? typeof(T).Name}: {message}";
 | 
			
		||||
        logger.Log(body, level, force);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void LogWarning<T>(this ILogger logger, T caller, string message, bool force = false) => Log(logger, caller, message, ILogger.Level.Info, force);
 | 
			
		||||
 | 
			
		||||
    public static void LogError<T>(this ILogger logger, T caller, string message, bool force = false)
 | 
			
		||||
    {
 | 
			
		||||
        Log(logger, caller, message, ILogger.Level.Error, force);
 | 
			
		||||
        Log(logger, caller, $"{nameof(StackTrace)}:{Environment.NewLine}{new StackTrace()}");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void LogException<T>(this ILogger logger, T caller, Exception exception, bool force = false)
 | 
			
		||||
    {
 | 
			
		||||
        Log(logger, caller, $"Message: {exception.Message}", ILogger.Level.Error, force);
 | 
			
		||||
        Log(logger, caller, $"InnerException: {exception.InnerException}", ILogger.Level.Error, force);
 | 
			
		||||
        Log(logger, caller, $"{nameof(StackTrace)}:{Environment.NewLine}{exception.StackTrace}");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
			
		||||
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <TargetFramework>net8.0</TargetFramework>
 | 
			
		||||
    <TargetFramework>net9.0</TargetFramework>
 | 
			
		||||
    <ImplicitUsings>false</ImplicitUsings>
 | 
			
		||||
    <Nullable>enable</Nullable>
 | 
			
		||||
    <RootNamespace>Syntriax.Engine.Core</RootNamespace>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,21 +1,59 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Factory;
 | 
			
		||||
 | 
			
		||||
public static class TypeFactory
 | 
			
		||||
{
 | 
			
		||||
    public static T Get<T>(params object?[]? args) where T : class
 | 
			
		||||
    private static readonly ConcurrentDictionary<string, Type> registeredTypes = [];
 | 
			
		||||
 | 
			
		||||
    public static string GetTypeName(Type type) => type.FullName ?? throw new ArgumentException($"{type.Name} must be a resolvable type");
 | 
			
		||||
 | 
			
		||||
    public static T Get<T>(params object?[]? args) where T : class => (T)Get(typeof(T), args);
 | 
			
		||||
    public static object Get(string fullName, params object?[]? args) => Get(GetType(fullName), args);
 | 
			
		||||
    public static object Get(Type type, params object?[]? args)
 | 
			
		||||
    {
 | 
			
		||||
        T? result;
 | 
			
		||||
        object? result;
 | 
			
		||||
 | 
			
		||||
        if (args is not null && args.Length != 0)
 | 
			
		||||
            result = Activator.CreateInstance(typeof(T), args) as T;
 | 
			
		||||
            result = Activator.CreateInstance(type, args);
 | 
			
		||||
        else
 | 
			
		||||
            result = Activator.CreateInstance(typeof(T)) as T;
 | 
			
		||||
            result = Activator.CreateInstance(type);
 | 
			
		||||
 | 
			
		||||
        if (result is null)
 | 
			
		||||
            throw new Exception($"{typeof(T).Name} of type {typeof(T).Name} could not be created.");
 | 
			
		||||
            throw new Exception($"Type {type.Name} could not be created.");
 | 
			
		||||
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static Type GetType(string fullName)
 | 
			
		||||
    {
 | 
			
		||||
        if (registeredTypes.TryGetValue(fullName, out Type? result))
 | 
			
		||||
            return result;
 | 
			
		||||
 | 
			
		||||
        ReloadTypes();
 | 
			
		||||
 | 
			
		||||
        if (registeredTypes.TryGetValue(fullName, out Type? reloadedType))
 | 
			
		||||
            return reloadedType;
 | 
			
		||||
 | 
			
		||||
        throw new Exception($"Type {fullName} could not be found in the current domain.");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void ReloadTypes()
 | 
			
		||||
    {
 | 
			
		||||
        registeredTypes.Clear();
 | 
			
		||||
 | 
			
		||||
        IEnumerable<Type> domainTypes = AppDomain.CurrentDomain
 | 
			
		||||
            .GetAssemblies()
 | 
			
		||||
            .SelectMany(a => a.GetTypes());
 | 
			
		||||
 | 
			
		||||
        // TODO: Replace this
 | 
			
		||||
        // There are some system & compiler generated types with duplicated names, 
 | 
			
		||||
        // it is ugly it will cause headaches in the future because it will not 
 | 
			
		||||
        // throw an error if there's a type with an unintended duplicate name
 | 
			
		||||
        foreach (Type type in domainTypes)
 | 
			
		||||
            registeredTypes.TryAdd(GetTypeName(type), type);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@ using System;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
public static class DelegateHelpers
 | 
			
		||||
public static class DelegateExtensions
 | 
			
		||||
{
 | 
			
		||||
    public static void InvokeSafe(this Delegate @delegate, params object?[] args)
 | 
			
		||||
    {
 | 
			
		||||
							
								
								
									
										7
									
								
								Engine.Core/Helpers/Progression/IProgressionTracker.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								Engine.Core/Helpers/Progression/IProgressionTracker.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
public interface IProgressionTracker : IReadOnlyProgressionTracker
 | 
			
		||||
{
 | 
			
		||||
    void Set(float progression, string status);
 | 
			
		||||
    void Reset();
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,13 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
public interface IReadOnlyProgressionTracker
 | 
			
		||||
{
 | 
			
		||||
    event ProgressionUpdatedEventHandler? OnUpdated;
 | 
			
		||||
    event ProgressionEndedEventHandler? OnEnded;
 | 
			
		||||
 | 
			
		||||
    float Progression { get; }
 | 
			
		||||
    string Status { get; }
 | 
			
		||||
 | 
			
		||||
    delegate void ProgressionUpdatedEventHandler(IReadOnlyProgressionTracker sender, float previousProgression, string previousStatus);
 | 
			
		||||
    delegate void ProgressionEndedEventHandler(IReadOnlyProgressionTracker sender);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										36
									
								
								Engine.Core/Helpers/Progression/ProgressionTracker.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								Engine.Core/Helpers/Progression/ProgressionTracker.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
public class ProgressionTracker : IProgressionTracker
 | 
			
		||||
{
 | 
			
		||||
    public event IReadOnlyProgressionTracker.ProgressionUpdatedEventHandler? OnUpdated = null;
 | 
			
		||||
    public event IReadOnlyProgressionTracker.ProgressionEndedEventHandler? OnEnded = null;
 | 
			
		||||
 | 
			
		||||
    public float Progression { get; private set; } = 0f;
 | 
			
		||||
    public string Status { get; private set; } = "Default";
 | 
			
		||||
 | 
			
		||||
    void IProgressionTracker.Set(float progression, string status)
 | 
			
		||||
    {
 | 
			
		||||
        if (Progression >= 1f)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        float previousProgression = Progression;
 | 
			
		||||
        string previousStatus = Status;
 | 
			
		||||
 | 
			
		||||
        Progression = progression.Clamp(Progression, 1f);
 | 
			
		||||
        Status = status;
 | 
			
		||||
 | 
			
		||||
        OnUpdated?.InvokeSafe(this, previousProgression, previousStatus);
 | 
			
		||||
 | 
			
		||||
        if (progression >= 1f)
 | 
			
		||||
            OnEnded?.InvokeSafe(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void IProgressionTracker.Reset()
 | 
			
		||||
    {
 | 
			
		||||
        Progression = 0f;
 | 
			
		||||
        Status = "Default";
 | 
			
		||||
 | 
			
		||||
        OnUpdated = null;
 | 
			
		||||
        OnEnded = null;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										9
									
								
								Engine.Core/Helpers/Progression/ProgressiveTask.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								Engine.Core/Helpers/Progression/ProgressiveTask.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
public record struct ProgressiveTask<T>(IReadOnlyProgressionTracker ProgressionTracker, Task<T> Task)
 | 
			
		||||
{
 | 
			
		||||
    public static implicit operator (IReadOnlyProgressionTracker progressionTracker, Task<T> task)(ProgressiveTask<T> value) => (value.ProgressionTracker, value.Task);
 | 
			
		||||
    public static implicit operator ProgressiveTask<T>((IReadOnlyProgressionTracker progressionTracker, Task<T> task) value) => new(value.progressionTracker, value.task);
 | 
			
		||||
}
 | 
			
		||||
@@ -30,6 +30,64 @@ public static class Math
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public const float DegreeToRadian = PI / 180f;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Gets one minus of given <see cref="T"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="value">The value <see cref="T"/>.</param>
 | 
			
		||||
    /// <returns>One minus of given <see cref="T"/>.</returns>
 | 
			
		||||
    public static T OneMinus<T>(T value) where T : INumber<T> => T.One - value;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Adds two <see cref="T"/>s.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="left">The first <see cref="T"/>.</param>
 | 
			
		||||
    /// <param name="value">The second <see cref="T"/>.</param>
 | 
			
		||||
    /// <returns>The sum of the two <see cref="T"/>s.</returns>
 | 
			
		||||
    public static T Add<T>(T left, T value) where T : INumber<T> => left + value;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Subtracts one <see cref="T"/> from another.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="left">The <see cref="T"/> to subtract from.</param>
 | 
			
		||||
    /// <param name="value">The <see cref="T"/> to subtract.</param>
 | 
			
		||||
    /// <returns>The result of subtracting the second <see cref="T"/> from the first.</returns>
 | 
			
		||||
    public static T Subtract<T>(T left, T value) where T : INumber<T> => left - value;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Multiplies a <see cref="T"/> by a scalar value.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="left">The <see cref="T"/>.</param>
 | 
			
		||||
    /// <param name="multiplier">The scalar value.</param>
 | 
			
		||||
    /// <returns>The result of multiplying the <see cref="T"/> by the scalar value.</returns>
 | 
			
		||||
    public static T Multiply<T>(T left, T multiplier) where T : INumber<T> => left * multiplier;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Divides a <see cref="T"/> by a scalar value.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="left">The <see cref="T"/>.</param>
 | 
			
		||||
    /// <param name="divider">The scalar value.</param>
 | 
			
		||||
    /// <returns>The result of dividing the <see cref="T"/> by the scalar value.</returns>
 | 
			
		||||
    public static T Divide<T>(T left, T divider) where T : INumber<T> => left / divider;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Returns the true mathematical modulus of a <see cref="T"/> value. 
 | 
			
		||||
    /// Unlike the remainder operator (%), this result is always non-negative,
 | 
			
		||||
    /// even when the <paramref name="value"/> operand is negative.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <typeparam name="T">A numeric type that implements <see cref="INumber{T}"/>.</typeparam>
 | 
			
		||||
    /// <param name="value">The dividend <see cref="T"/> value.</param>
 | 
			
		||||
    /// <param name="modulus">The modulus <see cref="T"/> value (must be non-zero).</param>
 | 
			
		||||
    /// <returns>
 | 
			
		||||
    /// The non-negative remainder of <paramref name="value"/> divided by <paramref name="modulus"/>.
 | 
			
		||||
    /// </returns>
 | 
			
		||||
    public static T Mod<T>(T value, T modulus) where T : INumber<T>
 | 
			
		||||
    {
 | 
			
		||||
        T result = value % modulus;
 | 
			
		||||
        if (result < T.Zero)
 | 
			
		||||
            result += modulus;
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Returns the absolute value of a number.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
@@ -190,6 +248,15 @@ public static class Math
 | 
			
		||||
    /// <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);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Rounds a number to an 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);
 | 
			
		||||
    public enum RoundMode { Ceil, Floor };
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Returns the square of a number.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,24 @@ namespace Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
public static class MathExtensions
 | 
			
		||||
{
 | 
			
		||||
    /// <inheritdoc cref="Math.OneMinus{T}(T)" />
 | 
			
		||||
    public static T OneMinus<T>(this T value) where T : INumber<T> => Math.OneMinus(value);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Math.Add{T}(T, T)" />
 | 
			
		||||
    public static T Add<T>(this T left, T value) where T : INumber<T> => Math.Add(left, value);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Math.Subtract{T}(T, T)" />
 | 
			
		||||
    public static T Subtract<T>(this T left, T value) where T : INumber<T> => Math.Subtract(left, value);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Math.Multiply{T}(T, T)" />
 | 
			
		||||
    public static T Multiply<T>(this T left, T multiplier) where T : INumber<T> => Math.Multiply(left, multiplier);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Math.Divide{T}(T, T)" />
 | 
			
		||||
    public static T Divide<T>(this T left, T divider) where T : INumber<T> => Math.Divide(left, divider);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Math.Mod{T}(T, T)" />
 | 
			
		||||
    public static T Mod<T>(this T value, T modulus) where T : INumber<T> => Math.Mod(value, modulus);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Math.Abs{T}(T)" />
 | 
			
		||||
    public static T Abs<T>(this T x) where T : INumber<T> => Math.Abs(x);
 | 
			
		||||
 | 
			
		||||
@@ -65,6 +83,9 @@ public static class MathExtensions
 | 
			
		||||
    /// <inheritdoc cref="Math.Round(float, int, MidpointRounding)" />
 | 
			
		||||
    public static float Round(this float x, int digits, MidpointRounding mode) => Math.Round(x, digits, 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);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Math.Sqr{T}(T)" />
 | 
			
		||||
    public static T Sqr<T>(this T x) where T : INumber<T> => Math.Sqr(x);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								Engine.Core/Preserver.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								Engine.Core/Preserver.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
namespace Syntriax.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.
 | 
			
		||||
    // I will hopefully one day fix it and remove this. 
 | 
			
		||||
    public static class Preserver
 | 
			
		||||
    {
 | 
			
		||||
        public static void Preserve() { }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										185
									
								
								Engine.Core/Primitives/ColorHSV.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										185
									
								
								Engine.Core/Primitives/ColorHSV.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,185 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents an HSV color.
 | 
			
		||||
/// </summary>
 | 
			
		||||
/// <param name="hue">Hue of the <see cref="ColorHSV"/>.</param>
 | 
			
		||||
/// <param name="saturation">Saturation of the <see cref="ColorHSV"/>.</param>
 | 
			
		||||
/// <param name="value">Value of the <see cref="ColorHSV"/>.</param>
 | 
			
		||||
/// <remarks>
 | 
			
		||||
/// 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)
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The Hue value of the <see cref="ColorHSV"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public readonly float Hue = hue.Clamp(0f, 1f);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The Saturation value of the <see cref="ColorHSV"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public readonly float Saturation = saturation.Clamp(0f, 1f);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The Value value of the <see cref="ColorHSV"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public readonly float Value = value.Clamp(0f, 1f);
 | 
			
		||||
 | 
			
		||||
    public static ColorHSV operator -(ColorHSV color) => new(color.Hue.OneMinus().Clamp(0f, 1f), color.Saturation.OneMinus().Clamp(0f, 1f), color.Value.OneMinus().Clamp(0f, 1f));
 | 
			
		||||
    public static ColorHSV operator +(ColorHSV left, ColorHSV right) => new((left.Hue + right.Hue).Clamp(0f, 1f), (left.Saturation + right.Saturation).Clamp(0f, 1f), (left.Value + right.Value).Clamp(0f, 1f));
 | 
			
		||||
    public static ColorHSV operator -(ColorHSV left, ColorHSV right) => new((left.Hue - right.Hue).Clamp(0f, 1f), (left.Saturation - right.Saturation).Clamp(0f, 1f), (left.Value - right.Value).Clamp(0f, 1f));
 | 
			
		||||
    public static ColorHSV operator *(ColorHSV left, ColorHSV right) => new((left.Hue * right.Hue).Clamp(0f, 1f), (left.Saturation * right.Saturation).Clamp(0f, 1f), (left.Value * right.Value).Clamp(0f, 1f));
 | 
			
		||||
    public static ColorHSV operator *(ColorHSV color, float value) => new((color.Hue * value).Clamp(0f, 1f), (color.Saturation * value).Clamp(0f, 1f), (color.Value * value).Clamp(0f, 1f));
 | 
			
		||||
    public static ColorHSV operator *(float value, ColorHSV color) => new((color.Hue * value).Clamp(0f, 1f), (color.Saturation * value).Clamp(0f, 1f), (color.Value * value).Clamp(0f, 1f));
 | 
			
		||||
    public static ColorHSV operator /(ColorHSV color, float value) => new((color.Hue / value).Clamp(0f, 1f), (color.Saturation / value).Clamp(0f, 1f), (color.Value / value).Clamp(0f, 1f));
 | 
			
		||||
    public static bool operator ==(ColorHSV left, ColorHSV right) => left.Hue.ApproximatelyEquals(right.Hue) && left.Saturation.ApproximatelyEquals(right.Saturation) && left.Value.ApproximatelyEquals(right.Value);
 | 
			
		||||
    public static bool operator !=(ColorHSV left, ColorHSV right) => !left.Hue.ApproximatelyEquals(right.Hue) || !left.Saturation.ApproximatelyEquals(right.Saturation) || !left.Value.ApproximatelyEquals(right.Value);
 | 
			
		||||
 | 
			
		||||
    public static implicit operator ColorHSV(ColorRGBA rgba) => (ColorRGB)rgba;
 | 
			
		||||
    public static implicit operator ColorHSV(ColorRGB rgb)
 | 
			
		||||
    {
 | 
			
		||||
        float hue;
 | 
			
		||||
        float saturation;
 | 
			
		||||
        float value;
 | 
			
		||||
 | 
			
		||||
        float rd = rgb.R / 255f;
 | 
			
		||||
        float gd = rgb.G / 255f;
 | 
			
		||||
        float bd = rgb.B / 255f;
 | 
			
		||||
 | 
			
		||||
        float max = Math.Max(rd, Math.Max(gd, bd));
 | 
			
		||||
        float min = Math.Min(rd, Math.Min(gd, bd));
 | 
			
		||||
        float delta = max - min;
 | 
			
		||||
 | 
			
		||||
        if (delta.ApproximatelyEquals(0))
 | 
			
		||||
            hue = 0f;
 | 
			
		||||
        else if (max.ApproximatelyEquals(rd))
 | 
			
		||||
            hue = 60f * ((gd - bd) / delta % 6f);
 | 
			
		||||
        else if (max.ApproximatelyEquals(gd))
 | 
			
		||||
            hue = 60f * (((bd - rd) / delta) + 2f);
 | 
			
		||||
        else
 | 
			
		||||
            hue = 60f * (((rd - gd) / delta) + 4f);
 | 
			
		||||
 | 
			
		||||
        if (hue < 0f)
 | 
			
		||||
            hue += 360f;
 | 
			
		||||
 | 
			
		||||
        hue /= 360f;
 | 
			
		||||
        saturation = max.ApproximatelyEquals(0f) ? 0f : delta / max;
 | 
			
		||||
        value = max;
 | 
			
		||||
 | 
			
		||||
        return new(hue, saturation, value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Inverts the given <see cref="ColorHSV"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="color">The <see cref="ColorHSV"/>.</param>
 | 
			
		||||
    /// <returns>The inverted <see cref="ColorHSV"/>.</returns>
 | 
			
		||||
    public static ColorHSV Invert(ColorHSV color) => -color;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Adds two <see cref="ColorHSV"/>s.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="left">The first <see cref="ColorHSV"/>.</param>
 | 
			
		||||
    /// <param name="right">The second <see cref="ColorHSV"/>.</param>
 | 
			
		||||
    /// <returns>The sum of the two <see cref="ColorHSV"/>s.</returns>
 | 
			
		||||
    public static ColorHSV Add(ColorHSV left, ColorHSV right) => left + right;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Subtracts one <see cref="ColorHSV"/> from another.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="left">The <see cref="ColorHSV"/> to subtract from.</param>
 | 
			
		||||
    /// <param name="right">The <see cref="ColorHSV"/> to subtract.</param>
 | 
			
		||||
    /// <returns>The result of subtracting the second <see cref="ColorHSV"/> from the first.</returns>
 | 
			
		||||
    public static ColorHSV Subtract(ColorHSV left, ColorHSV right) => left - right;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Multiplies a <see cref="ColorHSV"/> by a scalar value.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="color">The <see cref="ColorHSV"/>.</param>
 | 
			
		||||
    /// <param name="value">The scalar value.</param>
 | 
			
		||||
    /// <returns>The result of multiplying the <see cref="ColorHSV"/> by the scalar value.</returns>
 | 
			
		||||
    public static ColorHSV Multiply(ColorHSV color, float value) => color * value;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Divides a <see cref="ColorHSV"/> by a scalar value.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="color">The <see cref="ColorHSV"/>.</param>
 | 
			
		||||
    /// <param name="value">The scalar value.</param>
 | 
			
		||||
    /// <returns>The result of dividing the <see cref="ColorHSV"/> by the scalar value.</returns>
 | 
			
		||||
    public static ColorHSV Divide(ColorHSV color, float value) => color / value;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Calculates the <see cref="ColorHSV"/> from one point to another.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="from">The starting point.</param>
 | 
			
		||||
    /// <param name="to">The ending point.</param>
 | 
			
		||||
    /// <returns>The <see cref="ColorHSV"/> from the starting point to the ending point.</returns>
 | 
			
		||||
    public static ColorHSV FromTo(ColorHSV from, ColorHSV to) => to - from;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Performs linear interpolation between two <see cref="ColorHSV"/>s.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="from">The starting <see cref="ColorHSV"/> (t = 0).</param>
 | 
			
		||||
    /// <param name="to">The ending <see cref="ColorHSV"/> (t = 1).</param>
 | 
			
		||||
    /// <param name="t">The interpolation parameter.</param>
 | 
			
		||||
    /// <returns>The interpolated <see cref="ColorHSV"/>.</returns>
 | 
			
		||||
    public static ColorHSV Lerp(ColorHSV from, ColorHSV to, float t) => from + FromTo(from, to) * t;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Converts the <see cref="ColorHSV"/> to its string representation.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <returns>A string representation of the <see cref="ColorHSV"/>.</returns>
 | 
			
		||||
    public override string ToString() => $"{nameof(ColorHSV)}({Hue}, {Saturation}, {Value})";
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Checks if two <see cref="ColorHSV"/>s are approximately equal within a specified epsilon range.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="left">The first <see cref="ColorHSV"/>.</param>
 | 
			
		||||
    /// <param name="right">The second <see cref="ColorHSV"/>.</param>
 | 
			
		||||
    /// <param name="epsilon">The epsilon range.</param>
 | 
			
		||||
    /// <returns><see cref="true"/> if the <see cref="ColorHSV"/>s are approximately equal; otherwise, <see cref="false"/>.</returns>
 | 
			
		||||
    public static bool ApproximatelyEquals(ColorHSV left, ColorHSV right, float epsilon = float.Epsilon)
 | 
			
		||||
        => left.Hue.ApproximatelyEquals(right.Hue, epsilon) && left.Saturation.ApproximatelyEquals(right.Saturation, epsilon) && left.Value.ApproximatelyEquals(right.Value, epsilon);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Determines whether the specified object is equal to the current <see cref="ColorHSV"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <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 objVec && Hue.Equals(objVec.Hue) && Saturation.Equals(objVec.Saturation) && Value.Equals(objVec.Value);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Generates a hash code for the <see cref="ColorHSV"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <returns>A hash code for the <see cref="ColorHSV"/>.</returns>
 | 
			
		||||
    public override int GetHashCode() => System.HashCode.Combine(Hue, Saturation, Value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Provides extension methods for <see cref="ColorHSV"/> type.
 | 
			
		||||
/// </summary>
 | 
			
		||||
public static class ColorHSVExtensions
 | 
			
		||||
{
 | 
			
		||||
    /// <inheritdoc cref="ColorHSV.Add(ColorHSV, ColorHSV)" />
 | 
			
		||||
    public static ColorHSV Add(this ColorHSV color, ColorHSV value) => ColorHSV.Add(color, value);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="ColorHSV.Subtract(ColorHSV, ColorHSV)" />
 | 
			
		||||
    public static ColorHSV Subtract(this ColorHSV color, ColorHSV value) => ColorHSV.Subtract(color, value);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="ColorHSV.Multiply(ColorHSV, ColorHSV)" />
 | 
			
		||||
    public static ColorHSV Multiply(this ColorHSV color, float value) => ColorHSV.Multiply(color, value);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="ColorHSV.Divide(ColorHSV, ColorHSV)" />
 | 
			
		||||
    public static ColorHSV Divide(this ColorHSV color, float value) => ColorHSV.Divide(color, value);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="ColorHSV.FromTo(ColorHSV, ColorHSV)" />
 | 
			
		||||
    public static ColorHSV FromTo(this ColorHSV from, ColorHSV to) => ColorHSV.FromTo(from, to);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="ColorHSV.Lerp(ColorHSV, ColorHSV, float)" />
 | 
			
		||||
    public static ColorHSV Lerp(this ColorHSV from, ColorHSV to, float t) => ColorHSV.Lerp(from, to, t);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="ColorHSV.ApproximatelyEquals(ColorHSV, ColorHSV, float) " />
 | 
			
		||||
    public static bool ApproximatelyEquals(this ColorHSV left, ColorHSV right, float epsilon = float.Epsilon) => ColorHSV.ApproximatelyEquals(left, right, epsilon);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										164
									
								
								Engine.Core/Primitives/ColorRGB.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								Engine.Core/Primitives/ColorRGB.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,164 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents an RGB color.
 | 
			
		||||
/// </summary>
 | 
			
		||||
/// <param name="r">Red value of the <see cref="ColorRGB"/>.</param>
 | 
			
		||||
/// <param name="g">Green value of the <see cref="ColorRGB"/>.</param>
 | 
			
		||||
/// <param name="b">Blue value of the <see cref="ColorRGB"/>.</param>
 | 
			
		||||
/// <remarks>
 | 
			
		||||
/// 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)
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The Red value of the <see cref="ColorRGB"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public readonly byte R = r;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The Green value of the <see cref="ColorRGB"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public readonly byte G = g;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The Blue value of the <see cref="ColorRGB"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public readonly byte B = b;
 | 
			
		||||
 | 
			
		||||
    public static ColorRGB operator -(ColorRGB color) => new((byte)(255 - color.R), (byte)(255 - color.G), (byte)(255 - color.B));
 | 
			
		||||
    public static ColorRGB operator +(ColorRGB left, ColorRGB right) => new((byte)(left.R + right.R).Clamp(0, 255), (byte)(left.G + right.G).Clamp(0, 255), (byte)(left.B + right.B).Clamp(0, 255));
 | 
			
		||||
    public static ColorRGB operator -(ColorRGB left, ColorRGB right) => new((byte)(left.R - right.R).Clamp(0, 255), (byte)(left.G - right.G).Clamp(0, 255), (byte)(left.B - right.B).Clamp(0, 255));
 | 
			
		||||
    public static ColorRGB operator *(ColorRGB left, ColorRGB right) => new((byte)(left.R * right.R).Clamp(0, 255), (byte)(left.G * right.G).Clamp(0, 255), (byte)(left.B * right.B).Clamp(0, 255));
 | 
			
		||||
    public static ColorRGB operator *(ColorRGB color, float value) => new((byte)(color.R * value).Clamp(0, 255), (byte)(color.G * value).Clamp(0, 255), (byte)(color.B * value).Clamp(0, 255));
 | 
			
		||||
    public static ColorRGB operator *(float value, ColorRGB color) => new((byte)(color.R * value).Clamp(0, 255), (byte)(color.G * value).Clamp(0, 255), (byte)(color.B * value).Clamp(0, 255));
 | 
			
		||||
    public static ColorRGB operator /(ColorRGB color, float value) => new((byte)(color.R / value).Clamp(0, 255), (byte)(color.G / value).Clamp(0, 255), (byte)(color.B / value).Clamp(0, 255));
 | 
			
		||||
    public static bool operator ==(ColorRGB left, ColorRGB right) => left.R == right.R && left.G == right.G && left.B == right.B;
 | 
			
		||||
    public static bool operator !=(ColorRGB left, ColorRGB right) => left.R != right.R || left.G != right.G || left.B != right.B;
 | 
			
		||||
 | 
			
		||||
    public static implicit operator ColorRGB(ColorRGBA rgba) => new(rgba.R, rgba.G, rgba.B);
 | 
			
		||||
    public static implicit operator ColorRGB(ColorHSV hsv)
 | 
			
		||||
    {
 | 
			
		||||
        float hue = hsv.Hue * 360f;
 | 
			
		||||
        float chroma = hsv.Value * hsv.Saturation;
 | 
			
		||||
        float x = chroma * (1f - Math.Abs(hue / 60f % 2f - 1f));
 | 
			
		||||
        float m = hsv.Value - chroma;
 | 
			
		||||
 | 
			
		||||
        float r1 = 0f;
 | 
			
		||||
        float g1 = 0f;
 | 
			
		||||
        float b1 = 0f;
 | 
			
		||||
 | 
			
		||||
        if (hue < 60) { r1 = chroma; g1 = x; b1 = 0; }
 | 
			
		||||
        else if (hue < 120) { r1 = x; g1 = chroma; b1 = 0; }
 | 
			
		||||
        else if (hue < 180) { r1 = 0; g1 = chroma; b1 = x; }
 | 
			
		||||
        else if (hue < 240) { r1 = 0; g1 = x; b1 = chroma; }
 | 
			
		||||
        else if (hue < 300) { r1 = x; g1 = 0; b1 = chroma; }
 | 
			
		||||
        else if (hue <= 360) { r1 = chroma; g1 = 0; b1 = x; }
 | 
			
		||||
 | 
			
		||||
        byte r = (byte)Math.RoundToInt((r1 + m) * 255);
 | 
			
		||||
        byte g = (byte)Math.RoundToInt((g1 + m) * 255);
 | 
			
		||||
        byte b = (byte)Math.RoundToInt((b1 + m) * 255);
 | 
			
		||||
 | 
			
		||||
        return new(r, g, b);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Inverts the given <see cref="ColorRGB"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="color">The <see cref="ColorRGB"/>.</param>
 | 
			
		||||
    /// <returns>The inverted <see cref="ColorRGB"/>.</returns>
 | 
			
		||||
    public static ColorRGB Invert(ColorRGB color) => -color;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Adds two <see cref="ColorRGB"/>s.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="left">The first <see cref="ColorRGB"/>.</param>
 | 
			
		||||
    /// <param name="right">The second <see cref="ColorRGB"/>.</param>
 | 
			
		||||
    /// <returns>The sum of the two <see cref="ColorRGB"/>s.</returns>
 | 
			
		||||
    public static ColorRGB Add(ColorRGB left, ColorRGB right) => left + right;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Subtracts one <see cref="ColorRGB"/> from another.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="left">The <see cref="ColorRGB"/> to subtract from.</param>
 | 
			
		||||
    /// <param name="right">The <see cref="ColorRGB"/> to subtract.</param>
 | 
			
		||||
    /// <returns>The result of subtracting the second <see cref="ColorRGB"/> from the first.</returns>
 | 
			
		||||
    public static ColorRGB Subtract(ColorRGB left, ColorRGB right) => left - right;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Multiplies a <see cref="ColorRGB"/> by a scalar value.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="color">The <see cref="ColorRGB"/>.</param>
 | 
			
		||||
    /// <param name="value">The scalar value.</param>
 | 
			
		||||
    /// <returns>The result of multiplying the <see cref="ColorRGB"/> by the scalar value.</returns>
 | 
			
		||||
    public static ColorRGB Multiply(ColorRGB color, float value) => color * value;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Divides a <see cref="ColorRGB"/> by a scalar value.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="color">The <see cref="ColorRGB"/>.</param>
 | 
			
		||||
    /// <param name="value">The scalar value.</param>
 | 
			
		||||
    /// <returns>The result of dividing the <see cref="ColorRGB"/> by the scalar value.</returns>
 | 
			
		||||
    public static ColorRGB Divide(ColorRGB color, float value) => color / value;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Calculates the <see cref="ColorRGB"/> from one point to another.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="from">The starting point.</param>
 | 
			
		||||
    /// <param name="to">The ending point.</param>
 | 
			
		||||
    /// <returns>The <see cref="ColorRGB"/> from the starting point to the ending point.</returns>
 | 
			
		||||
    public static ColorRGB FromTo(ColorRGB from, ColorRGB to) => to - from;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Performs linear interpolation between two <see cref="ColorRGB"/>s.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="from">The starting <see cref="ColorRGB"/> (t = 0).</param>
 | 
			
		||||
    /// <param name="to">The ending <see cref="ColorRGB"/> (t = 1).</param>
 | 
			
		||||
    /// <param name="t">The interpolation parameter.</param>
 | 
			
		||||
    /// <returns>The interpolated <see cref="ColorRGB"/>.</returns>
 | 
			
		||||
    public static ColorRGB Lerp(ColorRGB from, ColorRGB to, float t) => from + FromTo(from, to) * t;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Converts the <see cref="ColorRGB"/> to its string representation.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <returns>A string representation of the <see cref="ColorRGB"/>.</returns>
 | 
			
		||||
    public override string ToString() => $"{nameof(ColorRGB)}({R}, {G}, {B})";
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Determines whether the specified object is equal to the current <see cref="ColorRGB"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <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 objVec && R.Equals(objVec.R) && G.Equals(objVec.G) && B.Equals(objVec.B);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Generates a hash code for the <see cref="ColorRGB"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <returns>A hash code for the <see cref="ColorRGB"/>.</returns>
 | 
			
		||||
    public override int GetHashCode() => System.HashCode.Combine(R, G, B);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Provides extension methods for <see cref="ColorRGB"/> type.
 | 
			
		||||
/// </summary>
 | 
			
		||||
public static class ColorRGBExtensions
 | 
			
		||||
{
 | 
			
		||||
    /// <inheritdoc cref="ColorRGB.Add(ColorRGB, ColorRGB)" />
 | 
			
		||||
    public static ColorRGB Add(this ColorRGB color, ColorRGB value) => ColorRGB.Add(color, value);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="ColorRGB.Subtract(ColorRGB, ColorRGB)" />
 | 
			
		||||
    public static ColorRGB Subtract(this ColorRGB color, ColorRGB value) => ColorRGB.Subtract(color, value);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="ColorRGB.Multiply(ColorRGB, ColorRGB)" />
 | 
			
		||||
    public static ColorRGB Multiply(this ColorRGB color, float value) => ColorRGB.Multiply(color, value);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="ColorRGB.Divide(ColorRGB, ColorRGB)" />
 | 
			
		||||
    public static ColorRGB Divide(this ColorRGB color, float value) => ColorRGB.Divide(color, value);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="ColorRGB.FromTo(ColorRGB, ColorRGB)" />
 | 
			
		||||
    public static ColorRGB FromTo(this ColorRGB from, ColorRGB to) => ColorRGB.FromTo(from, to);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="ColorRGB.Lerp(ColorRGB, ColorRGB, float)" />
 | 
			
		||||
    public static ColorRGB Lerp(this ColorRGB from, ColorRGB to, float t) => ColorRGB.Lerp(from, to, t);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										147
									
								
								Engine.Core/Primitives/ColorRGBA.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								Engine.Core/Primitives/ColorRGBA.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,147 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents an RGBA color.
 | 
			
		||||
/// </summary>
 | 
			
		||||
/// <param name="r">Red value of the <see cref="ColorRGBA"/>.</param>
 | 
			
		||||
/// <param name="g">Green value of the <see cref="ColorRGBA"/>.</param>
 | 
			
		||||
/// <param name="b">Blue value of the <see cref="ColorRGBA"/>.</param>
 | 
			
		||||
/// <param name="a">Alpha value of the <see cref="ColorRGBA"/>.</param>
 | 
			
		||||
/// <remarks>
 | 
			
		||||
/// 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)
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The Red value of the <see cref="ColorRGBA"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public readonly byte R = r;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The Green value of the <see cref="ColorRGBA"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public readonly byte G = g;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The Blue value of the <see cref="ColorRGBA"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public readonly byte B = b;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The Alpha value of the <see cref="ColorRGBA"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public readonly byte A = a;
 | 
			
		||||
 | 
			
		||||
    public static ColorRGBA operator -(ColorRGBA color) => new((byte)(255 - color.R), (byte)(255 - color.G), (byte)(255 - color.B), color.A);
 | 
			
		||||
    public static ColorRGBA operator +(ColorRGBA left, ColorRGBA right) => new((byte)(left.R + right.R).Clamp(0, 255), (byte)(left.G + right.G).Clamp(0, 255), (byte)(left.B + right.B).Clamp(0, 255), (byte)(left.A + right.A).Clamp(0, 255));
 | 
			
		||||
    public static ColorRGBA operator -(ColorRGBA left, ColorRGBA right) => new((byte)(left.R - right.R).Clamp(0, 255), (byte)(left.G - right.G).Clamp(0, 255), (byte)(left.B - right.B).Clamp(0, 255), (byte)(left.A - right.A).Clamp(0, 255));
 | 
			
		||||
    public static ColorRGBA operator *(ColorRGBA left, ColorRGBA right) => new((byte)(left.R * right.R).Clamp(0, 255), (byte)(left.G * right.G).Clamp(0, 255), (byte)(left.B * right.B).Clamp(0, 255), (byte)(left.A * right.A).Clamp(0, 255));
 | 
			
		||||
    public static ColorRGBA operator *(ColorRGBA color, float value) => new((byte)(color.R * value).Clamp(0, 255), (byte)(color.G * value).Clamp(0, 255), (byte)(color.B * value).Clamp(0, 255), (byte)(color.A * value).Clamp(0, 255));
 | 
			
		||||
    public static ColorRGBA operator *(float value, ColorRGBA color) => new((byte)(color.R * value).Clamp(0, 255), (byte)(color.G * value).Clamp(0, 255), (byte)(color.B * value).Clamp(0, 255), (byte)(color.A * value).Clamp(0, 255));
 | 
			
		||||
    public static ColorRGBA operator /(ColorRGBA color, float value) => new((byte)(color.R / value).Clamp(0, 255), (byte)(color.G / value).Clamp(0, 255), (byte)(color.B / value).Clamp(0, 255), (byte)(color.A / value).Clamp(0, 255));
 | 
			
		||||
    public static bool operator ==(ColorRGBA left, ColorRGBA right) => left.R == right.R && left.G == right.G && left.B == right.B && left.A == right.A;
 | 
			
		||||
    public static bool operator !=(ColorRGBA left, ColorRGBA right) => left.R != right.R || left.G != right.G || left.B != right.B || left.A != right.A;
 | 
			
		||||
 | 
			
		||||
    public static implicit operator ColorRGBA(ColorRGB rgb) => new(rgb.R, rgb.G, rgb.B, 255);
 | 
			
		||||
    public static implicit operator ColorRGBA(ColorHSV hsv) => (ColorRGB)hsv;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Inverts the given <see cref="ColorRGBA"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="color">The <see cref="ColorRGBA"/>.</param>
 | 
			
		||||
    /// <returns>The inverted <see cref="ColorRGBA"/>.</returns>
 | 
			
		||||
    public static ColorRGBA Invert(ColorRGBA color) => -color;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Adds two <see cref="ColorRGBA"/>s.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="left">The first <see cref="ColorRGBA"/>.</param>
 | 
			
		||||
    /// <param name="right">The second <see cref="ColorRGBA"/>.</param>
 | 
			
		||||
    /// <returns>The sum of the two <see cref="ColorRGBA"/>s.</returns>
 | 
			
		||||
    public static ColorRGBA Add(ColorRGBA left, ColorRGBA right) => left + right;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Subtracts one <see cref="ColorRGBA"/> from another.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="left">The <see cref="ColorRGBA"/> to subtract from.</param>
 | 
			
		||||
    /// <param name="right">The <see cref="ColorRGBA"/> to subtract.</param>
 | 
			
		||||
    /// <returns>The result of subtracting the second <see cref="ColorRGBA"/> from the first.</returns>
 | 
			
		||||
    public static ColorRGBA Subtract(ColorRGBA left, ColorRGBA right) => left - right;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Multiplies a <see cref="ColorRGBA"/> by a scalar value.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="color">The <see cref="ColorRGBA"/>.</param>
 | 
			
		||||
    /// <param name="value">The scalar value.</param>
 | 
			
		||||
    /// <returns>The result of multiplying the <see cref="ColorRGBA"/> by the scalar value.</returns>
 | 
			
		||||
    public static ColorRGBA Multiply(ColorRGBA color, float value) => color * value;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Divides a <see cref="ColorRGBA"/> by a scalar value.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="color">The <see cref="ColorRGBA"/>.</param>
 | 
			
		||||
    /// <param name="value">The scalar value.</param>
 | 
			
		||||
    /// <returns>The result of dividing the <see cref="ColorRGBA"/> by the scalar value.</returns>
 | 
			
		||||
    public static ColorRGBA Divide(ColorRGBA color, float value) => color / value;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Calculates the <see cref="ColorRGBA"/> from one point to another.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="from">The starting point.</param>
 | 
			
		||||
    /// <param name="to">The ending point.</param>
 | 
			
		||||
    /// <returns>The <see cref="ColorRGBA"/> from the starting point to the ending point.</returns>
 | 
			
		||||
    public static ColorRGBA FromTo(ColorRGBA from, ColorRGBA to) => to - from;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Performs linear interpolation between two <see cref="ColorRGBA"/>s.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="from">The starting <see cref="ColorRGBA"/> (t = 0).</param>
 | 
			
		||||
    /// <param name="to">The ending <see cref="ColorRGBA"/> (t = 1).</param>
 | 
			
		||||
    /// <param name="t">The interpolation parameter.</param>
 | 
			
		||||
    /// <returns>The interpolated <see cref="ColorRGBA"/>.</returns>
 | 
			
		||||
    public static ColorRGBA Lerp(ColorRGBA from, ColorRGBA to, float t) => from + FromTo(from, to) * t;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Converts the <see cref="ColorRGBA"/> to its string representation.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <returns>A string representation of the <see cref="ColorRGBA"/>.</returns>
 | 
			
		||||
    public override string ToString() => $"{nameof(ColorRGBA)}({R}, {G}, {B}, {A})";
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Determines whether the specified object is equal to the current <see cref="ColorRGBA"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <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 objVec && R.Equals(objVec.R) && G.Equals(objVec.G) && B.Equals(objVec.B) && A.Equals(objVec.A);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Generates a hash code for the <see cref="ColorRGBA"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <returns>A hash code for the <see cref="ColorRGBA"/>.</returns>
 | 
			
		||||
    public override int GetHashCode() => System.HashCode.Combine(R, G, B, A);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Provides extension methods for <see cref="ColorRGBA"/> type.
 | 
			
		||||
/// </summary>
 | 
			
		||||
public static class ColorRGBAExtensions
 | 
			
		||||
{
 | 
			
		||||
    /// <inheritdoc cref="ColorRGBA.Add(ColorRGBA, ColorRGBA)" />
 | 
			
		||||
    public static ColorRGBA Add(this ColorRGBA color, ColorRGBA value) => ColorRGBA.Add(color, value);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="ColorRGBA.Subtract(ColorRGBA, ColorRGBA)" />
 | 
			
		||||
    public static ColorRGBA Subtract(this ColorRGBA color, ColorRGBA value) => ColorRGBA.Subtract(color, value);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="ColorRGBA.Multiply(ColorRGBA, ColorRGBA)" />
 | 
			
		||||
    public static ColorRGBA Multiply(this ColorRGBA color, float value) => ColorRGBA.Multiply(color, value);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="ColorRGBA.Divide(ColorRGBA, ColorRGBA)" />
 | 
			
		||||
    public static ColorRGBA Divide(this ColorRGBA color, float value) => ColorRGBA.Divide(color, value);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="ColorRGBA.FromTo(ColorRGBA, ColorRGBA)" />
 | 
			
		||||
    public static ColorRGBA FromTo(this ColorRGBA from, ColorRGBA to) => ColorRGBA.FromTo(from, to);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="ColorRGBA.Lerp(ColorRGBA, ColorRGBA, float)" />
 | 
			
		||||
    public static ColorRGBA Lerp(this ColorRGBA from, ColorRGBA to, float t) => ColorRGBA.Lerp(from, to, t);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,3 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Diagnostics.CodeAnalysis;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
@@ -68,12 +67,12 @@ public readonly struct Line2D(Vector2D from, Vector2D to)
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public static float GetT(Line2D line, Vector2D point)
 | 
			
		||||
    {
 | 
			
		||||
        float fromX = MathF.Abs(line.From.X);
 | 
			
		||||
        float toX = MathF.Abs(line.To.X);
 | 
			
		||||
        float pointX = MathF.Abs(point.X);
 | 
			
		||||
        float fromX = Math.Abs(line.From.X);
 | 
			
		||||
        float toX = Math.Abs(line.To.X);
 | 
			
		||||
        float pointX = Math.Abs(point.X);
 | 
			
		||||
 | 
			
		||||
        float min = MathF.Min(fromX, toX);
 | 
			
		||||
        float max = MathF.Max(fromX, toX) - min;
 | 
			
		||||
        float min = Math.Min(fromX, toX);
 | 
			
		||||
        float max = Math.Max(fromX, toX) - min;
 | 
			
		||||
 | 
			
		||||
        pointX -= min;
 | 
			
		||||
 | 
			
		||||
@@ -114,8 +113,8 @@ public readonly struct Line2D(Vector2D from, Vector2D to)
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public static bool OnSegment(Line2D line, Vector2D point)
 | 
			
		||||
    {
 | 
			
		||||
        if (point.X <= MathF.Max(line.From.X, line.To.X) && point.X >= MathF.Min(line.From.X, line.To.X) &&
 | 
			
		||||
            point.Y <= MathF.Max(line.From.Y, line.To.Y) && point.Y >= MathF.Min(line.From.Y, line.To.Y))
 | 
			
		||||
        if (point.X <= Math.Max(line.From.X, line.To.X) && point.X >= Math.Min(line.From.X, line.To.X) &&
 | 
			
		||||
            point.Y <= Math.Max(line.From.Y, line.To.Y) && point.Y >= Math.Min(line.From.Y, line.To.Y))
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
@@ -173,7 +172,7 @@ public readonly struct Line2D(Vector2D from, Vector2D to)
 | 
			
		||||
 | 
			
		||||
        float t = (pointVector.X * edgeVector.X + pointVector.Y * edgeVector.Y) / (edgeVector.X * edgeVector.X + edgeVector.Y * edgeVector.Y);
 | 
			
		||||
 | 
			
		||||
        t = MathF.Max(0, MathF.Min(1, t));
 | 
			
		||||
        t = Math.Max(0, Math.Min(1, t));
 | 
			
		||||
 | 
			
		||||
        float closestX = line.From.X + t * edgeVector.X;
 | 
			
		||||
        float closestY = line.From.Y + t * edgeVector.Y;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,3 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
@@ -178,11 +176,11 @@ public readonly struct Quaternion(float x, float y, float z, float w)
 | 
			
		||||
        if (dot > 0.9995f)
 | 
			
		||||
            return Lerp(from, to, t);
 | 
			
		||||
 | 
			
		||||
        float angle = MathF.Acos(dot);
 | 
			
		||||
        float sinAngle = MathF.Sin(angle);
 | 
			
		||||
        float angle = Math.Acos(dot);
 | 
			
		||||
        float sinAngle = Math.Sin(angle);
 | 
			
		||||
 | 
			
		||||
        float fromWeight = MathF.Sin((1f - t) * angle) / sinAngle;
 | 
			
		||||
        float toWeight = MathF.Sin(t * angle) / sinAngle;
 | 
			
		||||
        float fromWeight = Math.Sin((1f - t) * angle) / sinAngle;
 | 
			
		||||
        float toWeight = Math.Sin(t * angle) / sinAngle;
 | 
			
		||||
 | 
			
		||||
        return from * fromWeight + to * toWeight;
 | 
			
		||||
    }
 | 
			
		||||
@@ -213,8 +211,8 @@ public readonly struct Quaternion(float x, float y, float z, float w)
 | 
			
		||||
    public static Quaternion FromAxisAngle(Vector3D axis, float angle)
 | 
			
		||||
    {
 | 
			
		||||
        float halfAngle = angle * .5f;
 | 
			
		||||
        float sinHalf = MathF.Sin(halfAngle);
 | 
			
		||||
        return new Quaternion(axis.X * sinHalf, axis.Y * sinHalf, axis.Z * sinHalf, MathF.Cos(halfAngle));
 | 
			
		||||
        float sinHalf = Math.Sin(halfAngle);
 | 
			
		||||
        return new Quaternion(axis.X * sinHalf, axis.Y * sinHalf, axis.Z * sinHalf, Math.Cos(halfAngle));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
@@ -301,7 +299,7 @@ public readonly struct Quaternion(float x, float y, float z, float w)
 | 
			
		||||
    /// Generates a hash code for the <see cref="Quaternion"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <returns>A hash code for the <see cref="Quaternion"/>.</returns>
 | 
			
		||||
    public override int GetHashCode() => HashCode.Combine(X, Y, Z);
 | 
			
		||||
    public override int GetHashCode() => System.HashCode.Combine(X, Y, Z);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
 
 | 
			
		||||
@@ -11,19 +11,33 @@ namespace Syntriax.Engine.Core;
 | 
			
		||||
/// Initializes a new instance of a <see cref="Shape2D"/> struct with the specified vertices.
 | 
			
		||||
/// </remarks>
 | 
			
		||||
[System.Diagnostics.DebuggerDisplay("Vertices Count: {Vertices.Count}")]
 | 
			
		||||
public readonly struct Shape2D(List<Vector2D> vertices) : IEnumerable<Vector2D>
 | 
			
		||||
public class Shape2D(List<Vector2D> vertices) : IEnumerable<Vector2D>
 | 
			
		||||
{
 | 
			
		||||
    public static readonly Shape2D Triangle = CreateNgon(3, Vector2D.Up);
 | 
			
		||||
    public static readonly Shape2D Square = CreateNgon(4, Vector2D.One);
 | 
			
		||||
    public static readonly Shape2D Pentagon = CreateNgon(5, Vector2D.Up);
 | 
			
		||||
    public static readonly Shape2D Hexagon = CreateNgon(6, Vector2D.Right);
 | 
			
		||||
    public static Shape2D Triangle => CreateNgon(3, Vector2D.Up);
 | 
			
		||||
    public static Shape2D Square => CreateNgon(4, Vector2D.One);
 | 
			
		||||
    public static Shape2D Pentagon => CreateNgon(5, Vector2D.Up);
 | 
			
		||||
    public static Shape2D Hexagon => CreateNgon(6, Vector2D.Right);
 | 
			
		||||
 | 
			
		||||
    private readonly List<Vector2D> _verticesList = vertices;
 | 
			
		||||
    public event ShapeUpdatedEventHandler? OnShapeUpdated = null;
 | 
			
		||||
 | 
			
		||||
    private List<Vector2D> _vertices = vertices;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Gets the vertices of the <see cref="Shape2D"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public IReadOnlyList<Vector2D> Vertices => _verticesList;
 | 
			
		||||
    public IReadOnlyList<Vector2D> Vertices
 | 
			
		||||
    {
 | 
			
		||||
        get => _vertices;
 | 
			
		||||
        set
 | 
			
		||||
        {
 | 
			
		||||
            _vertices.Clear();
 | 
			
		||||
 | 
			
		||||
            foreach (Vector2D vertex in value)
 | 
			
		||||
                _vertices.Add(vertex);
 | 
			
		||||
 | 
			
		||||
            OnShapeUpdated?.InvokeSafe(this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The vertex at the specified index.
 | 
			
		||||
@@ -207,13 +221,15 @@ public readonly struct Shape2D(List<Vector2D> vertices) : IEnumerable<Vector2D>
 | 
			
		||||
    /// <param name="from">The <see cref="Shape2D"/> to transform.</param>
 | 
			
		||||
    /// <param name="transform">The <see cref="ITransform2D"/> to apply.</param>
 | 
			
		||||
    /// <param name="to">The transformed <see cref="Shape2D"/>.</param>
 | 
			
		||||
    public static void Transform(Shape2D from, ITransform2D transform, ref Shape2D to)
 | 
			
		||||
    public static void Transform(Shape2D from, ITransform2D transform, Shape2D to)
 | 
			
		||||
    {
 | 
			
		||||
        to._verticesList.Clear();
 | 
			
		||||
        to._vertices.Clear();
 | 
			
		||||
 | 
			
		||||
        int count = from._verticesList.Count;
 | 
			
		||||
        int count = from._vertices.Count;
 | 
			
		||||
        for (int i = 0; i < count; i++)
 | 
			
		||||
            to._verticesList.Add(transform.Transform(from[i]));
 | 
			
		||||
            to._vertices.Add(transform.Transform(from[i]));
 | 
			
		||||
 | 
			
		||||
        to.OnShapeUpdated?.InvokeSafe(to);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
@@ -240,6 +256,8 @@ public readonly struct Shape2D(List<Vector2D> vertices) : IEnumerable<Vector2D>
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc/>
 | 
			
		||||
    IEnumerator IEnumerable.GetEnumerator() => Vertices.GetEnumerator();
 | 
			
		||||
 | 
			
		||||
    public delegate void ShapeUpdatedEventHandler(Shape2D shape2D);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
@@ -275,13 +293,13 @@ public static class Shape2DExtensions
 | 
			
		||||
    public static Shape2D Transform(this ITransform2D transform, Shape2D shape) => Shape2D.Transform(shape, transform);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Shape2D.Transform(Shape2D, ITransform2D, Shape2D)" />
 | 
			
		||||
    public static void Transform(this ITransform2D transform, Shape2D from, ref Shape2D to) => Shape2D.Transform(from, transform, ref to);
 | 
			
		||||
    public static void Transform(this ITransform2D transform, Shape2D from, Shape2D to) => Shape2D.Transform(from, transform, to);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Shape2D.Transform(Shape2D, ITransform2D)" />
 | 
			
		||||
    public static Shape2D Transform(this Shape2D shape, ITransform2D transform) => Shape2D.Transform(shape, transform);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Shape2D.Transform(Shape2D, ITransform2D, ref Shape2D)" />
 | 
			
		||||
    public static void Transform(this Shape2D from, ITransform2D transform, ref Shape2D to) => Shape2D.Transform(from, transform, ref to);
 | 
			
		||||
    /// <inheritdoc cref="Shape2D.Transform(Shape2D, ITransform2D,Shape2D)" />
 | 
			
		||||
    public static void Transform(this Shape2D from, ITransform2D transform, Shape2D to) => Shape2D.Transform(from, transform, to);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Shape2D.ApproximatelyEquals(Shape2D, Shape2D, float)" />
 | 
			
		||||
    public static bool ApproximatelyEquals(this Shape2D left, Shape2D right, float epsilon = float.Epsilon) => Shape2D.ApproximatelyEquals(left, right, epsilon);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,3 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
[System.Diagnostics.DebuggerDisplay("A: {A.ToString(), nq}, B: {B.ToString(), nq}, B: {C.ToString(), nq}")]
 | 
			
		||||
@@ -10,7 +8,7 @@ public readonly struct Triangle(Vector2D A, Vector2D B, Vector2D C)
 | 
			
		||||
    public readonly Vector2D C { get; init; } = C;
 | 
			
		||||
 | 
			
		||||
    public readonly float Area
 | 
			
		||||
        => .5f * MathF.Abs(
 | 
			
		||||
        => .5f * Math.Abs(
 | 
			
		||||
                A.X * (B.Y - C.Y) +
 | 
			
		||||
                B.X * (C.Y - A.Y) +
 | 
			
		||||
                C.X * (A.Y - B.Y)
 | 
			
		||||
@@ -25,7 +23,7 @@ public readonly struct Triangle(Vector2D A, Vector2D B, Vector2D C)
 | 
			
		||||
        float slopeBC = (triangle.C.Y - triangle.B.Y) / (triangle.C.X - triangle.B.X);
 | 
			
		||||
 | 
			
		||||
        Vector2D center;
 | 
			
		||||
        if (MathF.Abs(slopeAB - slopeBC) > float.Epsilon)
 | 
			
		||||
        if (Math.Abs(slopeAB - slopeBC) > float.Epsilon)
 | 
			
		||||
        {
 | 
			
		||||
            float x = (slopeAB * slopeBC * (triangle.A.Y - triangle.C.Y) + slopeBC * (triangle.A.X + triangle.B.X) - slopeAB * (triangle.B.X + triangle.C.X)) / (2f * (slopeBC - slopeAB));
 | 
			
		||||
            float y = -(x - (triangle.A.X + triangle.B.X) / 2f) / slopeAB + (triangle.A.Y + triangle.B.Y) / 2f;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,3 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
@@ -316,7 +314,7 @@ public readonly struct Vector2D(float x, float y)
 | 
			
		||||
    /// Generates a hash code for the <see cref="Vector2D"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <returns>A hash code for the <see cref="Vector2D"/>.</returns>
 | 
			
		||||
    public override int GetHashCode() => HashCode.Combine(X, Y);
 | 
			
		||||
    public override int GetHashCode() => System.HashCode.Combine(X, Y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,3 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
@@ -290,7 +288,7 @@ public readonly struct Vector3D(float x, float y, float z)
 | 
			
		||||
    /// Generates a hash code for the <see cref="Vector3D"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <returns>A hash code for the <see cref="Vector3D"/>.</returns>
 | 
			
		||||
    public override int GetHashCode() => HashCode.Combine(X, Y, Z);
 | 
			
		||||
    public override int GetHashCode() => System.HashCode.Combine(X, Y, Z);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,6 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Serialization;
 | 
			
		||||
 | 
			
		||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Class)]
 | 
			
		||||
public class IgnoreSerializationAttribute : Attribute;
 | 
			
		||||
@@ -0,0 +1,6 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Serialization;
 | 
			
		||||
 | 
			
		||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
 | 
			
		||||
public class SerializeAllAttribute : Attribute;
 | 
			
		||||
@@ -0,0 +1,6 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Serialization;
 | 
			
		||||
 | 
			
		||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
 | 
			
		||||
public class SerializeAttribute : Attribute;
 | 
			
		||||
							
								
								
									
										3
									
								
								Engine.Core/Serialization/EntityReference.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								Engine.Core/Serialization/EntityReference.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
namespace Syntriax.Engine.Core.Serialization;
 | 
			
		||||
 | 
			
		||||
public record class EntityReference(string? Id = null);
 | 
			
		||||
							
								
								
									
										39
									
								
								Engine.Core/Serialization/EntityRegistry.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								Engine.Core/Serialization/EntityRegistry.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Serialization;
 | 
			
		||||
 | 
			
		||||
public class EntityRegistry
 | 
			
		||||
{
 | 
			
		||||
    public event EntityRegisteredEventHandler? OnEntityRegistered = null!;
 | 
			
		||||
 | 
			
		||||
    private readonly Dictionary<string, Action<IEntity>?> assignCallbacks = [];
 | 
			
		||||
    private readonly Dictionary<string, IEntity> registeredEntities = [];
 | 
			
		||||
    public IReadOnlyDictionary<string, IEntity> RegisteredEntities => registeredEntities;
 | 
			
		||||
 | 
			
		||||
    public void Add(IEntity entity)
 | 
			
		||||
    {
 | 
			
		||||
        if (registeredEntities.TryAdd(entity.Id, entity))
 | 
			
		||||
            OnEntityRegistered?.InvokeSafe(this, entity);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void QueueAssign(string id, Action<IEntity> setMethod)
 | 
			
		||||
    {
 | 
			
		||||
        assignCallbacks.TryAdd(id, null);
 | 
			
		||||
        assignCallbacks[id] = assignCallbacks[id] + setMethod;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void AssignAll()
 | 
			
		||||
    {
 | 
			
		||||
        foreach ((string id, Action<IEntity>? action) in assignCallbacks)
 | 
			
		||||
            action?.InvokeSafe(registeredEntities[id]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void Reset()
 | 
			
		||||
    {
 | 
			
		||||
        assignCallbacks.Clear();
 | 
			
		||||
        registeredEntities.Clear();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public delegate void EntityRegisteredEventHandler(EntityRegistry sender, IEntity entity);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										18
									
								
								Engine.Core/Serialization/ISerializer.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								Engine.Core/Serialization/ISerializer.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Serialization;
 | 
			
		||||
 | 
			
		||||
public interface ISerializer
 | 
			
		||||
{
 | 
			
		||||
    object Deserialize(string configuration);
 | 
			
		||||
    object Deserialize(string configuration, Type type);
 | 
			
		||||
    T Deserialize<T>(string configuration);
 | 
			
		||||
 | 
			
		||||
    string Serialize(object instance);
 | 
			
		||||
 | 
			
		||||
    ProgressiveTask<object> DeserializeAsync(string configuration);
 | 
			
		||||
    ProgressiveTask<object> DeserializeAsync(string configuration, Type type);
 | 
			
		||||
    ProgressiveTask<T> DeserializeAsync<T>(string configuration);
 | 
			
		||||
 | 
			
		||||
    ProgressiveTask<string> SerializeAsync(object instance);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										157
									
								
								Engine.Core/Serialization/SerializedClass.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								Engine.Core/Serialization/SerializedClass.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,157 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core.Factory;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Serialization;
 | 
			
		||||
 | 
			
		||||
public class SerializedClass
 | 
			
		||||
{
 | 
			
		||||
    private const BindingFlags PRIVATE_BINDING_FLAGS = BindingFlags.Instance | BindingFlags.NonPublic;
 | 
			
		||||
    private const BindingFlags PUBLIC_BINDING_FLAGS = BindingFlags.Instance | BindingFlags.Public;
 | 
			
		||||
 | 
			
		||||
    public string Type { get; set; } = string.Empty;
 | 
			
		||||
    public Dictionary<string, object?> Public { get; set; } = [];
 | 
			
		||||
    public Dictionary<string, object?> Private { get; set; } = [];
 | 
			
		||||
 | 
			
		||||
    public SerializedClass() { }
 | 
			
		||||
    public SerializedClass(object @class)
 | 
			
		||||
    {
 | 
			
		||||
        UpdateClass(@class);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void UpdateClass(object @class)
 | 
			
		||||
    {
 | 
			
		||||
        Type type = @class.GetType();
 | 
			
		||||
        Type = type.FullName ?? type.Name;
 | 
			
		||||
 | 
			
		||||
        bool shouldSerializeAll = type.HasAttribute<SerializeAllAttribute>();
 | 
			
		||||
 | 
			
		||||
        Public.Clear();
 | 
			
		||||
        Private.Clear();
 | 
			
		||||
 | 
			
		||||
        foreach (PropertyInfo privatePropertyInfo in Utils.GetPropertyInfosIncludingBaseClasses(type, PRIVATE_BINDING_FLAGS))
 | 
			
		||||
        {
 | 
			
		||||
            if (privatePropertyInfo.HasAttribute<IgnoreSerializationAttribute>())
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            if (privatePropertyInfo.SetMethod is null)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            if (!shouldSerializeAll && !privatePropertyInfo.HasAttribute<SerializeAttribute>())
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            object? value = privatePropertyInfo.GetValue(@class);
 | 
			
		||||
            if (value is IEntity entity)
 | 
			
		||||
                Private.Add(privatePropertyInfo.Name, entity.Id);
 | 
			
		||||
            else
 | 
			
		||||
                Private.Add(privatePropertyInfo.Name, value);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        foreach (PropertyInfo publicPropertyInfo in Utils.GetPropertyInfosIncludingBaseClasses(type, PUBLIC_BINDING_FLAGS))
 | 
			
		||||
        {
 | 
			
		||||
            if (publicPropertyInfo.HasAttribute<IgnoreSerializationAttribute>())
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            if (publicPropertyInfo.SetMethod is null)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            if (!shouldSerializeAll && !publicPropertyInfo.HasAttribute<SerializeAttribute>())
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            object? value = publicPropertyInfo.GetValue(@class);
 | 
			
		||||
            if (value is IEntity entity)
 | 
			
		||||
                Public.Add(publicPropertyInfo.Name, entity.Id);
 | 
			
		||||
            else
 | 
			
		||||
                Public.Add(publicPropertyInfo.Name, value);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        foreach (FieldInfo privateFieldInfo in Utils.GetFieldInfosIncludingBaseClasses(type, PRIVATE_BINDING_FLAGS))
 | 
			
		||||
        {
 | 
			
		||||
            if (privateFieldInfo.HasAttribute<System.Runtime.CompilerServices.CompilerGeneratedAttribute>())
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            if (!shouldSerializeAll && !privateFieldInfo.HasAttribute<SerializeAttribute>())
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            object? value = privateFieldInfo.GetValue(@class);
 | 
			
		||||
            if (value is IEntity entity)
 | 
			
		||||
                Private.Add(privateFieldInfo.Name, entity.Id);
 | 
			
		||||
            else
 | 
			
		||||
                Private.Add(privateFieldInfo.Name, value);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        foreach (FieldInfo publicFieldInfo in Utils.GetFieldInfosIncludingBaseClasses(type, PUBLIC_BINDING_FLAGS))
 | 
			
		||||
        {
 | 
			
		||||
            if (publicFieldInfo.HasAttribute<System.Runtime.CompilerServices.CompilerGeneratedAttribute>())
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            if (!shouldSerializeAll && !publicFieldInfo.HasAttribute<SerializeAttribute>())
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            object? value = publicFieldInfo.GetValue(@class);
 | 
			
		||||
            if (value is IEntity entity)
 | 
			
		||||
                Public.Add(publicFieldInfo.Name, entity.Id);
 | 
			
		||||
            else
 | 
			
		||||
                Public.Add(publicFieldInfo.Name, value);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public object CreateInstance()
 | 
			
		||||
    {
 | 
			
		||||
        Type type = TypeFactory.GetType(Type);
 | 
			
		||||
        object instance = TypeFactory.Get(type);
 | 
			
		||||
 | 
			
		||||
        foreach ((string key, object? value) in Private)
 | 
			
		||||
            AssignVariable(key, type, instance, value, PRIVATE_BINDING_FLAGS);
 | 
			
		||||
 | 
			
		||||
        foreach ((string key, object? value) in Public)
 | 
			
		||||
            AssignVariable(key, type, instance, value, PUBLIC_BINDING_FLAGS);
 | 
			
		||||
 | 
			
		||||
        return instance;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public object CreateInstance(EntityRegistry? entityRegistry)
 | 
			
		||||
    {
 | 
			
		||||
        if (entityRegistry is null)
 | 
			
		||||
            return CreateInstance();
 | 
			
		||||
 | 
			
		||||
        Type type = TypeFactory.GetType(Type);
 | 
			
		||||
        object instance = TypeFactory.Get(type);
 | 
			
		||||
 | 
			
		||||
        foreach ((string key, object? value) in Private)
 | 
			
		||||
            AssignVariable(key, type, instance, value, PRIVATE_BINDING_FLAGS, entityRegistry);
 | 
			
		||||
 | 
			
		||||
        foreach ((string key, object? value) in Public)
 | 
			
		||||
            AssignVariable(key, type, instance, value, PUBLIC_BINDING_FLAGS, entityRegistry);
 | 
			
		||||
 | 
			
		||||
        return instance;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static void AssignVariable(string key, Type type, object instance, object? value, BindingFlags bindingFlags, EntityRegistry entityRegistry)
 | 
			
		||||
    {
 | 
			
		||||
        if (type.GetField(key, bindingFlags) is FieldInfo fieldInfo)
 | 
			
		||||
        {
 | 
			
		||||
            if (typeof(IEntity).IsAssignableFrom(fieldInfo.FieldType))
 | 
			
		||||
                entityRegistry.QueueAssign(value?.ToString() ?? "", (entity) => fieldInfo.SetValue(instance, entity));
 | 
			
		||||
            else
 | 
			
		||||
                fieldInfo.SetValue(instance, value);
 | 
			
		||||
        }
 | 
			
		||||
        else if (type.GetProperty(key, bindingFlags) is PropertyInfo propertyInfo)
 | 
			
		||||
        {
 | 
			
		||||
            if (typeof(IEntity).IsAssignableFrom(propertyInfo.PropertyType))
 | 
			
		||||
                entityRegistry.QueueAssign(value?.ToString() ?? "", (entity) => propertyInfo.SetValue(instance, entity));
 | 
			
		||||
            else
 | 
			
		||||
                propertyInfo.SetValue(instance, value);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static void AssignVariable(string key, Type type, object instance, object? value, BindingFlags bindingFlags)
 | 
			
		||||
    {
 | 
			
		||||
        if (type.GetField(key, bindingFlags) is FieldInfo fieldInfo)
 | 
			
		||||
            fieldInfo.SetValue(instance, value);
 | 
			
		||||
        else if (type.GetProperty(key, bindingFlags) is PropertyInfo propertyInfo)
 | 
			
		||||
            propertyInfo.SetValue(instance, value);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										13
									
								
								Engine.Core/Serialization/TypeContainer.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								Engine.Core/Serialization/TypeContainer.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Serialization;
 | 
			
		||||
 | 
			
		||||
public class TypeContainer
 | 
			
		||||
{
 | 
			
		||||
    public object? Value { get; set; } = string.Empty;
 | 
			
		||||
    public string Type { get; set; } = string.Empty;
 | 
			
		||||
 | 
			
		||||
    public TypeContainer() { }
 | 
			
		||||
    public TypeContainer(Type type) { Type = type.FullName ?? string.Empty; }
 | 
			
		||||
    public TypeContainer(object? value) { Value = value; Type = value?.GetType().FullName ?? string.Empty; }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										82
									
								
								Engine.Core/Serialization/Utils.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								Engine.Core/Serialization/Utils.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,82 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Serialization;
 | 
			
		||||
 | 
			
		||||
public static class Utils
 | 
			
		||||
{
 | 
			
		||||
    public static bool HasAttribute<T>(this MemberInfo memberInfo) where T : Attribute => memberInfo.GetCustomAttribute<T>() is not null;
 | 
			
		||||
    public static bool IsEnumerable(this Type type) => typeof(System.Collections.IEnumerable).IsAssignableFrom(type) && type != typeof(string);
 | 
			
		||||
 | 
			
		||||
    public static TypeData GetTypeData(this Type objectType)
 | 
			
		||||
    {
 | 
			
		||||
        List<EventInfo> eventInfos = objectType.GetEvents(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
 | 
			
		||||
            .OrderBy(ei => ei.Name)
 | 
			
		||||
            .ToList();
 | 
			
		||||
 | 
			
		||||
        List<FieldInfo> fieldInfos = GetFieldInfosIncludingBaseClasses(objectType, BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.NonPublic | BindingFlags.Public)
 | 
			
		||||
                .Where(pi => !eventInfos.Any(ei => pi.Name.CompareTo(ei.Name) == 0)).ToList();
 | 
			
		||||
 | 
			
		||||
        List<PropertyInfo> propertyInfos = GetPropertyInfosIncludingBaseClasses(objectType, BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.Public)
 | 
			
		||||
            .Where(pi => pi.SetMethod is not null && !eventInfos.Any(ei => pi.Name.CompareTo(ei.Name) == 0))
 | 
			
		||||
            .ToList();
 | 
			
		||||
 | 
			
		||||
        return new TypeData(fieldInfos, propertyInfos);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static List<FieldInfo> GetFieldInfosIncludingBaseClasses(Type type, BindingFlags bindingFlags)
 | 
			
		||||
    {
 | 
			
		||||
        if (type.BaseType is null)
 | 
			
		||||
            return [.. type.GetFields(bindingFlags)];
 | 
			
		||||
 | 
			
		||||
        Type currentType = type;
 | 
			
		||||
        FieldInfoComparer fieldComparer = new();
 | 
			
		||||
        HashSet<FieldInfo> fieldInfoList = new(type.GetFields(bindingFlags), fieldComparer);
 | 
			
		||||
 | 
			
		||||
        while (currentType.BaseType is Type baseType)
 | 
			
		||||
        {
 | 
			
		||||
            currentType = baseType;
 | 
			
		||||
            fieldInfoList.UnionWith(currentType!.GetFields(bindingFlags));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return [.. fieldInfoList.OrderBy(fi => fi.Name)];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static List<PropertyInfo> GetPropertyInfosIncludingBaseClasses(Type type, BindingFlags bindingFlags)
 | 
			
		||||
    {
 | 
			
		||||
        if (type.BaseType is null)
 | 
			
		||||
            return [.. type.GetProperties(bindingFlags)];
 | 
			
		||||
 | 
			
		||||
        Type currentType = type;
 | 
			
		||||
        PropertyInfoComparer propertyComparer = new();
 | 
			
		||||
        HashSet<PropertyInfo> propertyInfoList = new(type.GetProperties(bindingFlags), propertyComparer);
 | 
			
		||||
 | 
			
		||||
        while (currentType.BaseType is Type baseType)
 | 
			
		||||
        {
 | 
			
		||||
            currentType = baseType;
 | 
			
		||||
            propertyInfoList.UnionWith(currentType.GetProperties(bindingFlags));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return [.. propertyInfoList.OrderBy(pi => pi.Name)];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private class FieldInfoComparer : IEqualityComparer<FieldInfo>
 | 
			
		||||
    {
 | 
			
		||||
        public bool Equals(FieldInfo? x, FieldInfo? y) => x?.DeclaringType == y?.DeclaringType && x?.Name == y?.Name;
 | 
			
		||||
        public int GetHashCode(FieldInfo obj) => obj.Name.GetHashCode() ^ obj.DeclaringType!.GetHashCode();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private class PropertyInfoComparer : IEqualityComparer<PropertyInfo>
 | 
			
		||||
    {
 | 
			
		||||
        public bool Equals(PropertyInfo? x, PropertyInfo? y) => x?.DeclaringType == y?.DeclaringType && x?.Name == y?.Name;
 | 
			
		||||
        public int GetHashCode(PropertyInfo obj) => obj.Name.GetHashCode() ^ obj.DeclaringType!.GetHashCode();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public record struct TypeData(IEnumerable<FieldInfo> Fields, IEnumerable<PropertyInfo> Properties)
 | 
			
		||||
{
 | 
			
		||||
    public static implicit operator (IEnumerable<FieldInfo> fields, IEnumerable<PropertyInfo> properties)(TypeData value) => (value.Fields, value.Properties);
 | 
			
		||||
    public static implicit operator TypeData((IEnumerable<FieldInfo> fields, IEnumerable<PropertyInfo> properties) value) => new(value.fields, value.properties);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,3 +1,5 @@
 | 
			
		||||
using Syntriax.Engine.Core.Serialization;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
[System.Diagnostics.DebuggerDisplay("Name: {UniverseObject.Name, nq} Position: {Position.ToString(), nq}, Scale: {Scale.ToString(), nq}, Rotation: {Rotation}")]
 | 
			
		||||
@@ -11,9 +13,9 @@ public class Transform2D : Behaviour, ITransform2D
 | 
			
		||||
    private Vector2D _scale = Vector2D.One;
 | 
			
		||||
    private float _rotation = 0f;
 | 
			
		||||
 | 
			
		||||
    private Vector2D _localPosition = Vector2D.Zero;
 | 
			
		||||
    private Vector2D _localScale = Vector2D.One;
 | 
			
		||||
    private float _localRotation = 0f;
 | 
			
		||||
    [Serialize] private Vector2D _localPosition = Vector2D.Zero;
 | 
			
		||||
    [Serialize] private Vector2D _localScale = Vector2D.One;
 | 
			
		||||
    [Serialize] private float _localRotation = 0f;
 | 
			
		||||
 | 
			
		||||
    private ITransform2D? parentTransform = null;
 | 
			
		||||
 | 
			
		||||
@@ -29,7 +31,7 @@ public class Transform2D : Behaviour, ITransform2D
 | 
			
		||||
            _position = value;
 | 
			
		||||
 | 
			
		||||
            UpdateLocalPosition();
 | 
			
		||||
            OnPositionChanged?.InvokeSafe(this, _position);
 | 
			
		||||
            OnPositionChanged?.InvokeSafe(this, previousPosition);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -110,7 +110,7 @@ public class Universe : BaseEntity, IUniverse
 | 
			
		||||
 | 
			
		||||
    public void Update(UniverseTime engineTime)
 | 
			
		||||
    {
 | 
			
		||||
        Debug.AssertHelpers.AssertInitialized(this);
 | 
			
		||||
        Debug.Assert.AssertInitialized(this);
 | 
			
		||||
 | 
			
		||||
        UnscaledTime = engineTime;
 | 
			
		||||
        Time = new(TimeSpan.FromTicks((long)(Time.TimeSinceStart.Ticks + engineTime.DeltaSpan.Ticks * TimeScale)), TimeSpan.FromTicks((long)(engineTime.DeltaSpan.Ticks * TimeScale)));
 | 
			
		||||
@@ -125,7 +125,7 @@ public class Universe : BaseEntity, IUniverse
 | 
			
		||||
 | 
			
		||||
    public void PreDraw()
 | 
			
		||||
    {
 | 
			
		||||
        Debug.AssertHelpers.AssertInitialized(this);
 | 
			
		||||
        Debug.Assert.AssertInitialized(this);
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < UniverseObjects.Count; i++)
 | 
			
		||||
            UniverseObjects[i].BehaviourController.UpdatePreDraw();
 | 
			
		||||
 
 | 
			
		||||
@@ -156,6 +156,7 @@ public class UniverseObject : BaseEntity, IUniverseObject
 | 
			
		||||
    {
 | 
			
		||||
        base.InitializeInternal();
 | 
			
		||||
        _behaviourController ??= Factory.BehaviourControllerFactory.Instantiate(this);
 | 
			
		||||
        _behaviourController.Initialize();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public UniverseObject()
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ public class Collider2DShapeBehaviour : Collider2DBehaviourBase, IShapeCollider2
 | 
			
		||||
    private Shape2D _shapeWorld = Shape2D.Square.CreateCopy();
 | 
			
		||||
    private Shape2D _shapeLocal = Shape2D.Square;
 | 
			
		||||
 | 
			
		||||
    public override void CalculateCollider() => Transform.Transform(ShapeLocal, ref _shapeWorld);
 | 
			
		||||
    public override void CalculateCollider() => ShapeLocal.Transform(Transform, _shapeWorld);
 | 
			
		||||
 | 
			
		||||
    public Collider2DShapeBehaviour() { }
 | 
			
		||||
    public Collider2DShapeBehaviour(Shape2D shape)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
			
		||||
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <TargetFramework>net8.0</TargetFramework>
 | 
			
		||||
    <TargetFramework>net9.0</TargetFramework>
 | 
			
		||||
    <ImplicitUsings>disable</ImplicitUsings>
 | 
			
		||||
    <Nullable>enable</Nullable>
 | 
			
		||||
    <RootNamespace>Syntriax.Engine.Physics2D</RootNamespace>
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@ using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Physics2D;
 | 
			
		||||
 | 
			
		||||
public static partial class Physics2D
 | 
			
		||||
public static class Physics2D
 | 
			
		||||
{
 | 
			
		||||
    public static bool Overlaps(this Shape2D shape, Vector2D point) => Overlaps(shape, point, out float _);
 | 
			
		||||
    public static bool Overlaps(this Shape2D shape, Vector2D point, out float depth)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								Engine.Physics2D/Preserver.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								Engine.Physics2D/Preserver.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
namespace Syntriax.Engine.Physics2D
 | 
			
		||||
{
 | 
			
		||||
    // 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.
 | 
			
		||||
    // I will hopefully one day fix it and remove this. 
 | 
			
		||||
    public static class Preserver
 | 
			
		||||
    {
 | 
			
		||||
        public static void Preserve() { }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,13 @@
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Serialization;
 | 
			
		||||
 | 
			
		||||
using YamlDotNet.Serialization;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Serializers.Yaml;
 | 
			
		||||
 | 
			
		||||
public interface IEngineTypeYamlConverter : IYamlTypeConverter
 | 
			
		||||
{
 | 
			
		||||
    YamlSerializer Serializer { get; set; }
 | 
			
		||||
    EntityRegistry EntityRegistry { get; set; }
 | 
			
		||||
    IProgressionTracker ProgressionTracker { get; set; }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,88 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Serialization;
 | 
			
		||||
 | 
			
		||||
using YamlDotNet.Core;
 | 
			
		||||
using YamlDotNet.Core.Events;
 | 
			
		||||
using YamlDotNet.Serialization;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Serializers.Yaml;
 | 
			
		||||
 | 
			
		||||
public class BehaviourControllerConverter : EngineTypeYamlSerializerBase<IBehaviourController>
 | 
			
		||||
{
 | 
			
		||||
    private const string BEHAVIOURS_SCALAR_NAME = "Behaviours";
 | 
			
		||||
 | 
			
		||||
    public override IBehaviourController? Read(IParser parser, Type type, ObjectDeserializer rootDeserializer)
 | 
			
		||||
    {
 | 
			
		||||
        bool isTrackingController = ProgressionTracker.Progression.ApproximatelyEquals(0f);
 | 
			
		||||
        ProgressionTracker.Set(isTrackingController ? .25f : ProgressionTracker.Progression, $"Reading behaviour controller");
 | 
			
		||||
 | 
			
		||||
        string id;
 | 
			
		||||
 | 
			
		||||
        IBehaviourController behaviourController;
 | 
			
		||||
        IStateEnable stateEnable;
 | 
			
		||||
        List<IBehaviour> behaviours;
 | 
			
		||||
 | 
			
		||||
        parser.Consume<MappingStart>();
 | 
			
		||||
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(nameof(IBehaviourController.Id)) != 0)
 | 
			
		||||
            throw new();
 | 
			
		||||
        id = parser.Consume<Scalar>().Value;
 | 
			
		||||
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(SERIALIZED_SCALAR_NAME) != 0)
 | 
			
		||||
            throw new();
 | 
			
		||||
        SerializedClass instanceSerializedClass = (SerializedClass)rootDeserializer(typeof(SerializedClass))!;
 | 
			
		||||
        ProgressionTracker.Set(isTrackingController ? .5f : ProgressionTracker.Progression, $"Creating {instanceSerializedClass.Type}");
 | 
			
		||||
        behaviourController = (IBehaviourController)instanceSerializedClass.CreateInstance(EntityRegistry);
 | 
			
		||||
 | 
			
		||||
        string value = parser.Consume<Scalar>().Value;
 | 
			
		||||
        if (value.CompareTo(nameof(IBehaviourController.StateEnable)) != 0)
 | 
			
		||||
            throw new();
 | 
			
		||||
        stateEnable = (IStateEnable)rootDeserializer(typeof(IStateEnable))!;
 | 
			
		||||
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(BEHAVIOURS_SCALAR_NAME) != 0)
 | 
			
		||||
            throw new();
 | 
			
		||||
        behaviours = (List<IBehaviour>)rootDeserializer(typeof(List<IBehaviour>))!;
 | 
			
		||||
 | 
			
		||||
        parser.Consume<MappingEnd>();
 | 
			
		||||
 | 
			
		||||
        behaviourController.Id = id;
 | 
			
		||||
 | 
			
		||||
        stateEnable.Assign(behaviourController);
 | 
			
		||||
        behaviourController.Assign(stateEnable);
 | 
			
		||||
 | 
			
		||||
        foreach (IBehaviour behaviour in behaviours)
 | 
			
		||||
            behaviourController.AddBehaviour(behaviour);
 | 
			
		||||
 | 
			
		||||
        ProgressionTracker.Set(isTrackingController ? 1f : ProgressionTracker.Progression, $"Created {instanceSerializedClass.Type}");
 | 
			
		||||
        return behaviourController;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public override void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
 | 
			
		||||
    {
 | 
			
		||||
        IBehaviourController behaviourController = (IBehaviourController)value!;
 | 
			
		||||
 | 
			
		||||
        bool isTrackingController = ProgressionTracker.Progression.ApproximatelyEquals(0f);
 | 
			
		||||
        ProgressionTracker.Set(isTrackingController ? .25f : ProgressionTracker.Progression, $"Serializing behaviour controller");
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new MappingStart());
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new Scalar(nameof(IBehaviourController.Id)));
 | 
			
		||||
        emitter.Emit(new Scalar(behaviourController.Id));
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new Scalar(SERIALIZED_SCALAR_NAME));
 | 
			
		||||
        serializer(new SerializedClass(behaviourController));
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new Scalar(nameof(IBehaviourController.StateEnable)));
 | 
			
		||||
        serializer(behaviourController.StateEnable);
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new Scalar(BEHAVIOURS_SCALAR_NAME));
 | 
			
		||||
        serializer(behaviourController.GetBehaviours<IBehaviour>().Where(b => !b.GetType().HasAttribute<IgnoreSerializationAttribute>()));
 | 
			
		||||
 | 
			
		||||
        ProgressionTracker.Set(isTrackingController ? 1f : ProgressionTracker.Progression, $"Serialized behaviour controller");
 | 
			
		||||
        emitter.Emit(new MappingEnd());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,81 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Serialization;
 | 
			
		||||
 | 
			
		||||
using YamlDotNet.Core;
 | 
			
		||||
using YamlDotNet.Core.Events;
 | 
			
		||||
using YamlDotNet.Serialization;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Serializers.Yaml;
 | 
			
		||||
 | 
			
		||||
public class BehaviourConverter : EngineTypeYamlSerializerBase<IBehaviour>
 | 
			
		||||
{
 | 
			
		||||
    public override IBehaviour? Read(IParser parser, Type type, ObjectDeserializer rootDeserializer)
 | 
			
		||||
    {
 | 
			
		||||
        bool isTrackingController = ProgressionTracker.Progression.ApproximatelyEquals(0f);
 | 
			
		||||
        ProgressionTracker.Set(isTrackingController ? .25f : ProgressionTracker.Progression, $"Reading behaviour information");
 | 
			
		||||
 | 
			
		||||
        string id;
 | 
			
		||||
        int priority;
 | 
			
		||||
 | 
			
		||||
        IBehaviour behaviour;
 | 
			
		||||
        IStateEnable stateEnable;
 | 
			
		||||
 | 
			
		||||
        parser.Consume<MappingStart>();
 | 
			
		||||
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(nameof(IBehaviour.Id)) != 0)
 | 
			
		||||
            throw new();
 | 
			
		||||
        id = parser.Consume<Scalar>().Value;
 | 
			
		||||
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(nameof(IBehaviour.Priority)) != 0)
 | 
			
		||||
            throw new();
 | 
			
		||||
        priority = int.Parse(parser.Consume<Scalar>().Value);
 | 
			
		||||
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(SERIALIZED_SCALAR_NAME) != 0)
 | 
			
		||||
            throw new();
 | 
			
		||||
        SerializedClass instanceSerializedClass = (SerializedClass)rootDeserializer(typeof(SerializedClass))!;
 | 
			
		||||
        ProgressionTracker.Set(isTrackingController ? .5f : ProgressionTracker.Progression, $"Creating {instanceSerializedClass.Type}");
 | 
			
		||||
        behaviour = (IBehaviour)instanceSerializedClass.CreateInstance(EntityRegistry);
 | 
			
		||||
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(nameof(IBehaviour.StateEnable)) != 0)
 | 
			
		||||
            throw new();
 | 
			
		||||
        stateEnable = (IStateEnable)rootDeserializer(typeof(IStateEnable))!;
 | 
			
		||||
 | 
			
		||||
        parser.Consume<MappingEnd>();
 | 
			
		||||
 | 
			
		||||
        behaviour.Id = id;
 | 
			
		||||
        behaviour.Priority = priority;
 | 
			
		||||
 | 
			
		||||
        stateEnable.Assign(behaviour);
 | 
			
		||||
        behaviour.Assign(stateEnable);
 | 
			
		||||
 | 
			
		||||
        ProgressionTracker.Set(isTrackingController ? 1f : ProgressionTracker.Progression, $"Created {instanceSerializedClass.Type}");
 | 
			
		||||
        return behaviour;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public override void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
 | 
			
		||||
    {
 | 
			
		||||
        IBehaviour behaviour = (IBehaviour)value!;
 | 
			
		||||
 | 
			
		||||
        bool isTrackingController = ProgressionTracker.Progression.ApproximatelyEquals(0f);
 | 
			
		||||
        ProgressionTracker.Set(isTrackingController ? .25f : ProgressionTracker.Progression, $"Serializing behaviour");
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new MappingStart());
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new Scalar(nameof(IBehaviour.Id)));
 | 
			
		||||
        emitter.Emit(new Scalar(behaviour.Id));
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new Scalar(nameof(IBehaviour.Priority)));
 | 
			
		||||
        emitter.Emit(new Scalar(behaviour.Priority.ToString()));
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new Scalar(SERIALIZED_SCALAR_NAME));
 | 
			
		||||
        serializer(new SerializedClass(behaviour));
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new Scalar(nameof(IBehaviour.StateEnable)));
 | 
			
		||||
        serializer(behaviour.StateEnable);
 | 
			
		||||
 | 
			
		||||
        ProgressionTracker.Set(isTrackingController ? 1f : ProgressionTracker.Progression, $"Serialized behaviour");
 | 
			
		||||
        emitter.Emit(new MappingEnd());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,33 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Serialization;
 | 
			
		||||
 | 
			
		||||
using YamlDotNet.Core;
 | 
			
		||||
using YamlDotNet.Serialization;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Serializers.Yaml;
 | 
			
		||||
 | 
			
		||||
public abstract class EngineTypeYamlSerializerBase<T> : IEngineTypeYamlConverter
 | 
			
		||||
{
 | 
			
		||||
    protected const string SERIALIZED_SCALAR_NAME = "Properties";
 | 
			
		||||
 | 
			
		||||
    public EntityRegistry EntityRegistry { get; set; } = null!;
 | 
			
		||||
    public YamlSerializer Serializer { get; set; } = null!;
 | 
			
		||||
    public IProgressionTracker ProgressionTracker { get; set; } = null!;
 | 
			
		||||
 | 
			
		||||
    public bool Accepts(Type type) => typeof(T).IsAssignableFrom(type);
 | 
			
		||||
 | 
			
		||||
    public abstract T? Read(IParser parser, Type type, ObjectDeserializer rootDeserializer);
 | 
			
		||||
    public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
 | 
			
		||||
    {
 | 
			
		||||
        T? result = Read(parser, type, rootDeserializer);
 | 
			
		||||
 | 
			
		||||
        if (result is IEntity entity)
 | 
			
		||||
            EntityRegistry.Add(entity);
 | 
			
		||||
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public abstract void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer);
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,41 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
using YamlDotNet.Core;
 | 
			
		||||
using YamlDotNet.Core.Events;
 | 
			
		||||
using YamlDotNet.Serialization;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Serializers.Yaml;
 | 
			
		||||
 | 
			
		||||
public class AABBConverter : EngineTypeYamlSerializerBase<AABB>
 | 
			
		||||
{
 | 
			
		||||
    public override AABB Read(IParser parser, Type type, ObjectDeserializer rootDeserializer)
 | 
			
		||||
    {
 | 
			
		||||
        parser.Consume<MappingStart>();
 | 
			
		||||
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(nameof(AABB.LowerBoundary)) != 0)
 | 
			
		||||
            throw new ArgumentException($"{nameof(AABB)} mapping must start with {nameof(AABB.LowerBoundary)}");
 | 
			
		||||
        Vector2D lowerBoundary = (Vector2D)rootDeserializer(typeof(Vector2D))!;
 | 
			
		||||
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(nameof(AABB.UpperBoundary)) != 0)
 | 
			
		||||
            throw new ArgumentException($"{nameof(AABB)} mapping must end with {nameof(AABB.UpperBoundary)}");
 | 
			
		||||
        Vector2D upperBoundary = (Vector2D)rootDeserializer(typeof(Vector2D))!;
 | 
			
		||||
 | 
			
		||||
        parser.Consume<MappingEnd>();
 | 
			
		||||
 | 
			
		||||
        return new AABB(lowerBoundary, upperBoundary);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public override void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
 | 
			
		||||
    {
 | 
			
		||||
        AABB aabb = (AABB)value!;
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new MappingStart());
 | 
			
		||||
        emitter.Emit(new Scalar(nameof(AABB.LowerBoundary)));
 | 
			
		||||
        serializer(aabb.LowerBoundary, typeof(Vector2D));
 | 
			
		||||
        emitter.Emit(new Scalar(nameof(AABB.UpperBoundary)));
 | 
			
		||||
        serializer(aabb.UpperBoundary, typeof(Vector2D));
 | 
			
		||||
        emitter.Emit(new MappingEnd());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,41 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
using YamlDotNet.Core;
 | 
			
		||||
using YamlDotNet.Core.Events;
 | 
			
		||||
using YamlDotNet.Serialization;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Serializers.Yaml;
 | 
			
		||||
 | 
			
		||||
public class CircleConverter : EngineTypeYamlSerializerBase<Circle>
 | 
			
		||||
{
 | 
			
		||||
    public override Circle Read(IParser parser, Type type, ObjectDeserializer rootDeserializer)
 | 
			
		||||
    {
 | 
			
		||||
        parser.Consume<MappingStart>();
 | 
			
		||||
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(nameof(Circle.Center)) != 0)
 | 
			
		||||
            throw new ArgumentException($"{nameof(Circle)} mapping must start with {nameof(Circle.Center)}");
 | 
			
		||||
        Vector2D lowerBoundary = (Vector2D)rootDeserializer(typeof(Vector2D))!;
 | 
			
		||||
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(nameof(Circle.Radius)) != 0)
 | 
			
		||||
            throw new ArgumentException($"{nameof(Circle)} mapping must end with {nameof(Circle.Radius)}");
 | 
			
		||||
        float radius = (float)rootDeserializer(typeof(float))!;
 | 
			
		||||
 | 
			
		||||
        parser.Consume<MappingEnd>();
 | 
			
		||||
 | 
			
		||||
        return new Circle(lowerBoundary, radius);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public override void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
 | 
			
		||||
    {
 | 
			
		||||
        Circle circle = (Circle)value!;
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new MappingStart());
 | 
			
		||||
        emitter.Emit(new Scalar(nameof(Circle.Center)));
 | 
			
		||||
        serializer(circle.Center, typeof(Vector2D));
 | 
			
		||||
        emitter.Emit(new Scalar(nameof(Circle.Radius)));
 | 
			
		||||
        serializer(circle.Radius, typeof(float));
 | 
			
		||||
        emitter.Emit(new MappingEnd());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,28 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
using YamlDotNet.Core;
 | 
			
		||||
using YamlDotNet.Core.Events;
 | 
			
		||||
using YamlDotNet.Serialization;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Serializers.Yaml;
 | 
			
		||||
 | 
			
		||||
public class ColorHSVConverter : EngineTypeYamlSerializerBase<ColorHSV>
 | 
			
		||||
{
 | 
			
		||||
    private static readonly int SUBSTRING_START_LENGTH = nameof(ColorHSV).Length + 1;
 | 
			
		||||
 | 
			
		||||
    public override ColorHSV Read(IParser parser, Type type, ObjectDeserializer rootDeserializer)
 | 
			
		||||
    {
 | 
			
		||||
        string value = parser.Consume<Scalar>().Value;
 | 
			
		||||
        string insideParenthesis = value[SUBSTRING_START_LENGTH..^1];
 | 
			
		||||
        string[] values = insideParenthesis.Split(", ");
 | 
			
		||||
        return new ColorHSV(float.Parse(values[0]), float.Parse(values[1]), float.Parse(values[2]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public override void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
 | 
			
		||||
    {
 | 
			
		||||
        ColorHSV hsv = (ColorHSV)value!;
 | 
			
		||||
        emitter.Emit(new Scalar($"{nameof(ColorHSV)}({hsv.Hue}, {hsv.Saturation}, {hsv.Value})"));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,28 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
using YamlDotNet.Core;
 | 
			
		||||
using YamlDotNet.Core.Events;
 | 
			
		||||
using YamlDotNet.Serialization;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Serializers.Yaml;
 | 
			
		||||
 | 
			
		||||
public class ColorRGBAConverter : EngineTypeYamlSerializerBase<ColorRGBA>
 | 
			
		||||
{
 | 
			
		||||
    private static readonly int SUBSTRING_START_LENGTH = nameof(ColorRGBA).Length + 1;
 | 
			
		||||
 | 
			
		||||
    public override ColorRGBA Read(IParser parser, Type type, ObjectDeserializer rootDeserializer)
 | 
			
		||||
    {
 | 
			
		||||
        string value = parser.Consume<Scalar>().Value;
 | 
			
		||||
        string insideParenthesis = value[SUBSTRING_START_LENGTH..^1];
 | 
			
		||||
        string[] values = insideParenthesis.Split(", ");
 | 
			
		||||
        return new ColorRGBA(byte.Parse(values[0]), byte.Parse(values[1]), byte.Parse(values[2]), byte.Parse(values[3]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public override void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
 | 
			
		||||
    {
 | 
			
		||||
        ColorRGBA rgb = (ColorRGBA)value!;
 | 
			
		||||
        emitter.Emit(new Scalar($"{nameof(ColorRGBA)}({rgb.R}, {rgb.G}, {rgb.B}, {rgb.A})"));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,28 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
using YamlDotNet.Core;
 | 
			
		||||
using YamlDotNet.Core.Events;
 | 
			
		||||
using YamlDotNet.Serialization;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Serializers.Yaml;
 | 
			
		||||
 | 
			
		||||
public class ColorRGBConverter : EngineTypeYamlSerializerBase<ColorRGB>
 | 
			
		||||
{
 | 
			
		||||
    private static readonly int SUBSTRING_START_LENGTH = nameof(ColorRGB).Length + 1;
 | 
			
		||||
 | 
			
		||||
    public override ColorRGB Read(IParser parser, Type type, ObjectDeserializer rootDeserializer)
 | 
			
		||||
    {
 | 
			
		||||
        string value = parser.Consume<Scalar>().Value;
 | 
			
		||||
        string insideParenthesis = value[SUBSTRING_START_LENGTH..^1];
 | 
			
		||||
        string[] values = insideParenthesis.Split(", ");
 | 
			
		||||
        return new ColorRGB(byte.Parse(values[0]), byte.Parse(values[1]), byte.Parse(values[2]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public override void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
 | 
			
		||||
    {
 | 
			
		||||
        ColorRGB rgb = (ColorRGB)value!;
 | 
			
		||||
        emitter.Emit(new Scalar($"{nameof(ColorRGB)}({rgb.R}, {rgb.G}, {rgb.B})"));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,41 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
using YamlDotNet.Core;
 | 
			
		||||
using YamlDotNet.Core.Events;
 | 
			
		||||
using YamlDotNet.Serialization;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Serializers.Yaml;
 | 
			
		||||
 | 
			
		||||
public class Line2DConverter : EngineTypeYamlSerializerBase<Line2D>
 | 
			
		||||
{
 | 
			
		||||
    public override Line2D Read(IParser parser, Type type, ObjectDeserializer rootDeserializer)
 | 
			
		||||
    {
 | 
			
		||||
        parser.Consume<MappingStart>();
 | 
			
		||||
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(nameof(Line2D.From)) != 0)
 | 
			
		||||
            throw new ArgumentException($"{nameof(Line2D)} mapping must start with {nameof(Line2D.From)}");
 | 
			
		||||
        Vector2D from = (Vector2D)rootDeserializer(typeof(Vector2D))!;
 | 
			
		||||
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(nameof(Line2D.To)) != 0)
 | 
			
		||||
            throw new ArgumentException($"{nameof(Line2D)} mapping must end with {nameof(Line2D.To)}");
 | 
			
		||||
        Vector2D to = (Vector2D)rootDeserializer(typeof(Vector2D))!;
 | 
			
		||||
 | 
			
		||||
        parser.Consume<MappingEnd>();
 | 
			
		||||
 | 
			
		||||
        return new Line2D(from, to);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public override void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
 | 
			
		||||
    {
 | 
			
		||||
        Line2D line2D = (Line2D)value!;
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new MappingStart());
 | 
			
		||||
        emitter.Emit(new Scalar(nameof(Line2D.From)));
 | 
			
		||||
        serializer(line2D.From, typeof(Vector2D));
 | 
			
		||||
        emitter.Emit(new Scalar(nameof(Line2D.To)));
 | 
			
		||||
        serializer(line2D.To, typeof(Vector2D));
 | 
			
		||||
        emitter.Emit(new MappingEnd());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,41 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
using YamlDotNet.Core;
 | 
			
		||||
using YamlDotNet.Core.Events;
 | 
			
		||||
using YamlDotNet.Serialization;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Serializers.Yaml;
 | 
			
		||||
 | 
			
		||||
public class Line2DEquationConverter : EngineTypeYamlSerializerBase<Line2DEquation>
 | 
			
		||||
{
 | 
			
		||||
    public override Line2DEquation Read(IParser parser, Type type, ObjectDeserializer rootDeserializer)
 | 
			
		||||
    {
 | 
			
		||||
        parser.Consume<MappingStart>();
 | 
			
		||||
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(nameof(Line2DEquation.Slope)) != 0)
 | 
			
		||||
            throw new ArgumentException($"{nameof(Line2DEquation)} mapping must start with {nameof(Line2DEquation.Slope)}");
 | 
			
		||||
        float slope = (float)rootDeserializer(typeof(float))!;
 | 
			
		||||
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(nameof(Line2DEquation.OffsetY)) != 0)
 | 
			
		||||
            throw new ArgumentException($"{nameof(Line2DEquation)} mapping must end with {nameof(Line2DEquation.OffsetY)}");
 | 
			
		||||
        float offset = (float)rootDeserializer(typeof(float))!;
 | 
			
		||||
 | 
			
		||||
        parser.Consume<MappingEnd>();
 | 
			
		||||
 | 
			
		||||
        return new Line2DEquation(slope, offset);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public override void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
 | 
			
		||||
    {
 | 
			
		||||
        Line2DEquation line2DEquation = (Line2DEquation)value!;
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new MappingStart());
 | 
			
		||||
        emitter.Emit(new Scalar(nameof(Line2DEquation.Slope)));
 | 
			
		||||
        serializer(line2DEquation.Slope, typeof(float));
 | 
			
		||||
        emitter.Emit(new Scalar(nameof(Line2DEquation.OffsetY)));
 | 
			
		||||
        serializer(line2DEquation.OffsetY, typeof(float));
 | 
			
		||||
        emitter.Emit(new MappingEnd());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,41 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
using YamlDotNet.Core;
 | 
			
		||||
using YamlDotNet.Core.Events;
 | 
			
		||||
using YamlDotNet.Serialization;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Serializers.Yaml;
 | 
			
		||||
 | 
			
		||||
public class Projection1DConverter : EngineTypeYamlSerializerBase<Projection1D>
 | 
			
		||||
{
 | 
			
		||||
    public override Projection1D Read(IParser parser, Type type, ObjectDeserializer rootDeserializer)
 | 
			
		||||
    {
 | 
			
		||||
        parser.Consume<MappingStart>();
 | 
			
		||||
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(nameof(Projection1D.Min)) != 0)
 | 
			
		||||
            throw new ArgumentException($"{nameof(Projection1D)} mapping must start with {nameof(Projection1D.Min)}");
 | 
			
		||||
        float min = (float)rootDeserializer(typeof(float))!;
 | 
			
		||||
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(nameof(Projection1D.Max)) != 0)
 | 
			
		||||
            throw new ArgumentException($"{nameof(Projection1D)} mapping must end with {nameof(Projection1D.Max)}");
 | 
			
		||||
        float max = (float)rootDeserializer(typeof(float))!;
 | 
			
		||||
 | 
			
		||||
        parser.Consume<MappingEnd>();
 | 
			
		||||
 | 
			
		||||
        return new Projection1D(min, max);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public override void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
 | 
			
		||||
    {
 | 
			
		||||
        Projection1D projection1D = (Projection1D)value!;
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new MappingStart());
 | 
			
		||||
        emitter.Emit(new Scalar(nameof(Projection1D.Min)));
 | 
			
		||||
        serializer(projection1D.Min, typeof(float));
 | 
			
		||||
        emitter.Emit(new Scalar(nameof(Projection1D.Max)));
 | 
			
		||||
        serializer(projection1D.Max, typeof(float));
 | 
			
		||||
        emitter.Emit(new MappingEnd());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,28 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
using YamlDotNet.Core;
 | 
			
		||||
using YamlDotNet.Core.Events;
 | 
			
		||||
using YamlDotNet.Serialization;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Serializers.Yaml;
 | 
			
		||||
 | 
			
		||||
public class QuaternionConverter : EngineTypeYamlSerializerBase<Quaternion>
 | 
			
		||||
{
 | 
			
		||||
    private static readonly int SUBSTRING_START_LENGTH = nameof(Quaternion).Length + 1;
 | 
			
		||||
 | 
			
		||||
    public override Quaternion Read(IParser parser, Type type, ObjectDeserializer rootDeserializer)
 | 
			
		||||
    {
 | 
			
		||||
        string value = parser.Consume<Scalar>().Value;
 | 
			
		||||
        string insideParenthesis = value[SUBSTRING_START_LENGTH..^1];
 | 
			
		||||
        string[] values = insideParenthesis.Split(", ");
 | 
			
		||||
        return new Quaternion(float.Parse(values[0]), float.Parse(values[1]), float.Parse(values[2]), float.Parse(values[3]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public override void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
 | 
			
		||||
    {
 | 
			
		||||
        Quaternion quaternion = (Quaternion)value!;
 | 
			
		||||
        emitter.Emit(new Scalar($"{nameof(Quaternion)}({quaternion.X}, {quaternion.Y}, {quaternion.Z}, {quaternion.W})"));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,48 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
using YamlDotNet.Core;
 | 
			
		||||
using YamlDotNet.Core.Events;
 | 
			
		||||
using YamlDotNet.Serialization;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Serializers.Yaml;
 | 
			
		||||
 | 
			
		||||
public class Shape2DConverter : EngineTypeYamlSerializerBase<Shape2D>
 | 
			
		||||
{
 | 
			
		||||
    public override Shape2D Read(IParser parser, Type type, ObjectDeserializer rootDeserializer)
 | 
			
		||||
    {
 | 
			
		||||
        parser.Consume<MappingStart>();
 | 
			
		||||
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(nameof(Shape2D.Vertices)) != 0)
 | 
			
		||||
            throw new ArgumentException($"{nameof(Shape2D)} mapping have a {nameof(Shape2D.Vertices)}");
 | 
			
		||||
 | 
			
		||||
        parser.Consume<SequenceStart>();
 | 
			
		||||
 | 
			
		||||
        List<Vector2D> vertices = [];
 | 
			
		||||
 | 
			
		||||
        while (!parser.TryConsume<SequenceEnd>(out _))
 | 
			
		||||
        {
 | 
			
		||||
            Vector2D vertex = (Vector2D)rootDeserializer(typeof(Vector2D))!;
 | 
			
		||||
            vertices.Add(vertex);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        parser.Consume<MappingEnd>();
 | 
			
		||||
 | 
			
		||||
        return new Shape2D(vertices);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public override void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
 | 
			
		||||
    {
 | 
			
		||||
        Shape2D shape2D = (Shape2D)value!;
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new MappingStart());
 | 
			
		||||
        emitter.Emit(new Scalar(nameof(Shape2D.Vertices)));
 | 
			
		||||
        emitter.Emit(new SequenceStart(anchor: null, tag: null, isImplicit: false, style: SequenceStyle.Block));
 | 
			
		||||
        foreach (Vector2D vertex in shape2D.Vertices)
 | 
			
		||||
            serializer(vertex, typeof(Vector2D));
 | 
			
		||||
        emitter.Emit(new SequenceEnd());
 | 
			
		||||
        emitter.Emit(new MappingEnd());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,47 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
using YamlDotNet.Core;
 | 
			
		||||
using YamlDotNet.Core.Events;
 | 
			
		||||
using YamlDotNet.Serialization;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Serializers.Yaml;
 | 
			
		||||
 | 
			
		||||
public class TriangleConverter : EngineTypeYamlSerializerBase<Triangle>
 | 
			
		||||
{
 | 
			
		||||
    public override Triangle Read(IParser parser, Type type, ObjectDeserializer rootDeserializer)
 | 
			
		||||
    {
 | 
			
		||||
        parser.Consume<MappingStart>();
 | 
			
		||||
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(nameof(Triangle.A)) != 0)
 | 
			
		||||
            throw new ArgumentException($"{nameof(Triangle)} mapping must start with {nameof(Triangle.A)}");
 | 
			
		||||
        Vector2D a = (Vector2D)rootDeserializer(typeof(Vector2D))!;
 | 
			
		||||
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(nameof(Triangle.B)) != 0)
 | 
			
		||||
            throw new ArgumentException($"{nameof(Triangle)} mapping must have {nameof(Triangle.B)} after {nameof(Triangle.A)}");
 | 
			
		||||
        Vector2D b = (Vector2D)rootDeserializer(typeof(Vector2D))!;
 | 
			
		||||
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(nameof(Triangle.C)) != 0)
 | 
			
		||||
            throw new ArgumentException($"{nameof(Triangle)} mapping must end with {nameof(Triangle.C)}");
 | 
			
		||||
        Vector2D c = (Vector2D)rootDeserializer(typeof(Vector2D))!;
 | 
			
		||||
 | 
			
		||||
        parser.Consume<MappingEnd>();
 | 
			
		||||
 | 
			
		||||
        return new Triangle(a, b, c);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public override void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
 | 
			
		||||
    {
 | 
			
		||||
        Triangle aabb = (Triangle)value!;
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new MappingStart());
 | 
			
		||||
        emitter.Emit(new Scalar(nameof(Triangle.A)));
 | 
			
		||||
        serializer(aabb.A, typeof(Vector2D));
 | 
			
		||||
        emitter.Emit(new Scalar(nameof(Triangle.B)));
 | 
			
		||||
        serializer(aabb.B, typeof(Vector2D));
 | 
			
		||||
        emitter.Emit(new Scalar(nameof(Triangle.C)));
 | 
			
		||||
        serializer(aabb.C, typeof(Vector2D));
 | 
			
		||||
        emitter.Emit(new MappingEnd());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,28 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
using YamlDotNet.Core;
 | 
			
		||||
using YamlDotNet.Core.Events;
 | 
			
		||||
using YamlDotNet.Serialization;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Serializers.Yaml;
 | 
			
		||||
 | 
			
		||||
public class Vector2DConverter : EngineTypeYamlSerializerBase<Vector2D>
 | 
			
		||||
{
 | 
			
		||||
    private static readonly int SUBSTRING_START_LENGTH = nameof(Vector2D).Length + 1;
 | 
			
		||||
 | 
			
		||||
    public override Vector2D Read(IParser parser, Type type, ObjectDeserializer rootDeserializer)
 | 
			
		||||
    {
 | 
			
		||||
        string value = parser.Consume<Scalar>().Value;
 | 
			
		||||
        string insideParenthesis = value[SUBSTRING_START_LENGTH..^1];
 | 
			
		||||
        string[] values = insideParenthesis.Split(", ");
 | 
			
		||||
        return new Vector2D(float.Parse(values[0]), float.Parse(values[1]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public override void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
 | 
			
		||||
    {
 | 
			
		||||
        Vector2D vector2D = (Vector2D)value!;
 | 
			
		||||
        emitter.Emit(new Scalar($"{nameof(Vector2D)}({vector2D.X}, {vector2D.Y})"));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,28 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
using YamlDotNet.Core;
 | 
			
		||||
using YamlDotNet.Core.Events;
 | 
			
		||||
using YamlDotNet.Serialization;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Serializers.Yaml;
 | 
			
		||||
 | 
			
		||||
public class Vector3DConverter : EngineTypeYamlSerializerBase<Vector3D>
 | 
			
		||||
{
 | 
			
		||||
    private static readonly int SUBSTRING_START_LENGTH = nameof(Vector3D).Length + 1;
 | 
			
		||||
 | 
			
		||||
    public override Vector3D Read(IParser parser, Type type, ObjectDeserializer rootDeserializer)
 | 
			
		||||
    {
 | 
			
		||||
        string value = parser.Consume<Scalar>().Value;
 | 
			
		||||
        string insideParenthesis = value[SUBSTRING_START_LENGTH..^1];
 | 
			
		||||
        string[] values = insideParenthesis.Split(", ");
 | 
			
		||||
        return new Vector3D(float.Parse(values[0]), float.Parse(values[1]), float.Parse(values[2]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public override void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
 | 
			
		||||
    {
 | 
			
		||||
        Vector3D vector3D = (Vector3D)value!;
 | 
			
		||||
        emitter.Emit(new Scalar($"{nameof(Vector3D)}({vector3D.X}, {vector3D.Y}, {vector3D.Z})"));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,86 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Factory;
 | 
			
		||||
using Syntriax.Engine.Core.Serialization;
 | 
			
		||||
 | 
			
		||||
using YamlDotNet.Core;
 | 
			
		||||
using YamlDotNet.Core.Events;
 | 
			
		||||
using YamlDotNet.Serialization;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Serializers.Yaml;
 | 
			
		||||
 | 
			
		||||
public class SerializedClassConverter : EngineTypeYamlSerializerBase<SerializedClass>
 | 
			
		||||
{
 | 
			
		||||
    public override SerializedClass? Read(IParser parser, Type type, ObjectDeserializer rootDeserializer)
 | 
			
		||||
    {
 | 
			
		||||
        bool isTrackingController = ProgressionTracker.Progression.ApproximatelyEquals(0f);
 | 
			
		||||
        ProgressionTracker.Set(isTrackingController ? .1f : ProgressionTracker.Progression, $"Reading class");
 | 
			
		||||
 | 
			
		||||
        SerializedClass serializedClass = new();
 | 
			
		||||
        Dictionary<string, TypeContainer> publicDictionary = [];
 | 
			
		||||
        Dictionary<string, TypeContainer> privateDictionary = [];
 | 
			
		||||
 | 
			
		||||
        parser.Consume<MappingStart>();
 | 
			
		||||
 | 
			
		||||
        while (!parser.TryConsume<MappingEnd>(out _))
 | 
			
		||||
        {
 | 
			
		||||
            string key = parser.Consume<Scalar>().Value;
 | 
			
		||||
 | 
			
		||||
            switch (key)
 | 
			
		||||
            {
 | 
			
		||||
                case nameof(SerializedClass.Type): serializedClass.Type = parser.Consume<Scalar>().Value; break;
 | 
			
		||||
                case nameof(SerializedClass.Public): publicDictionary = (Dictionary<string, TypeContainer>)rootDeserializer(typeof(Dictionary<string, TypeContainer>))!; break;
 | 
			
		||||
                case nameof(SerializedClass.Private): privateDictionary = (Dictionary<string, TypeContainer>)rootDeserializer(typeof(Dictionary<string, TypeContainer>))!; break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        foreach ((string key, TypeContainer typeContainer) in publicDictionary)
 | 
			
		||||
            serializedClass.Public.Add(key, Serializer.InternalDeserialize(typeContainer.Value!.ToString()!, TypeFactory.GetType(typeContainer.Type)));
 | 
			
		||||
 | 
			
		||||
        foreach ((string key, TypeContainer typeContainer) in privateDictionary)
 | 
			
		||||
            serializedClass.Private.Add(key, Serializer.InternalDeserialize(typeContainer.Value!.ToString()!, TypeFactory.GetType(typeContainer.Type)));
 | 
			
		||||
 | 
			
		||||
        ProgressionTracker.Set(isTrackingController ? 1f : ProgressionTracker.Progression, $"Read {serializedClass.Type}");
 | 
			
		||||
        return serializedClass;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public override void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
 | 
			
		||||
    {
 | 
			
		||||
        SerializedClass serializedClass = (SerializedClass)value!;
 | 
			
		||||
 | 
			
		||||
        bool isTrackingController = ProgressionTracker.Progression.ApproximatelyEquals(0f);
 | 
			
		||||
        ProgressionTracker.Set(isTrackingController ? .25f : ProgressionTracker.Progression, $"Serializing {serializedClass.Type}");
 | 
			
		||||
 | 
			
		||||
        Dictionary<string, TypeContainer> publics = [];
 | 
			
		||||
        Dictionary<string, TypeContainer> privates = [];
 | 
			
		||||
 | 
			
		||||
        foreach ((string key, object? @object) in serializedClass.Public.Where(v => !v.GetType().HasAttribute<IgnoreSerializationAttribute>()))
 | 
			
		||||
            publics.Add(key, new TypeContainer(@object));
 | 
			
		||||
 | 
			
		||||
        foreach ((string key, object? @object) in serializedClass.Private.Where(v => !v.GetType().HasAttribute<IgnoreSerializationAttribute>()))
 | 
			
		||||
            privates.Add(key, new TypeContainer(@object));
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new MappingStart());
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new Scalar(nameof(SerializedClass.Type)));
 | 
			
		||||
        emitter.Emit(new Scalar(serializedClass.Type));
 | 
			
		||||
 | 
			
		||||
        if (publics.Count > 0)
 | 
			
		||||
        {
 | 
			
		||||
            emitter.Emit(new Scalar(nameof(SerializedClass.Public)));
 | 
			
		||||
            serializer(publics);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (privates.Count > 0)
 | 
			
		||||
        {
 | 
			
		||||
            emitter.Emit(new Scalar(nameof(SerializedClass.Private)));
 | 
			
		||||
            serializer(privates);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ProgressionTracker.Set(isTrackingController ? 1f : ProgressionTracker.Progression, $"Serialized {serializedClass.Type}");
 | 
			
		||||
        emitter.Emit(new MappingEnd());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,60 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Serialization;
 | 
			
		||||
 | 
			
		||||
using YamlDotNet.Core;
 | 
			
		||||
using YamlDotNet.Core.Events;
 | 
			
		||||
using YamlDotNet.Serialization;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Serializers.Yaml;
 | 
			
		||||
 | 
			
		||||
public class StateEnableConverter : EngineTypeYamlSerializerBase<IStateEnable>
 | 
			
		||||
{
 | 
			
		||||
    public override IStateEnable? Read(IParser parser, Type type, ObjectDeserializer rootDeserializer)
 | 
			
		||||
    {
 | 
			
		||||
        bool isTrackingController = ProgressionTracker.Progression.ApproximatelyEquals(0f);
 | 
			
		||||
        ProgressionTracker.Set(isTrackingController ? .25f : ProgressionTracker.Progression, $"Reading state enable");
 | 
			
		||||
 | 
			
		||||
        bool enabled;
 | 
			
		||||
 | 
			
		||||
        IStateEnable stateEnable;
 | 
			
		||||
 | 
			
		||||
        parser.Consume<MappingStart>();
 | 
			
		||||
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(nameof(IStateEnable.Enabled)) != 0)
 | 
			
		||||
            throw new();
 | 
			
		||||
        enabled = bool.Parse(parser.Consume<Scalar>().Value);
 | 
			
		||||
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(SERIALIZED_SCALAR_NAME) != 0)
 | 
			
		||||
            throw new();
 | 
			
		||||
        SerializedClass instanceSerializedClass = (SerializedClass)rootDeserializer(typeof(SerializedClass))!;
 | 
			
		||||
        stateEnable = (IStateEnable)instanceSerializedClass.CreateInstance(EntityRegistry);
 | 
			
		||||
 | 
			
		||||
        parser.Consume<MappingEnd>();
 | 
			
		||||
 | 
			
		||||
        stateEnable.Enabled = enabled;
 | 
			
		||||
 | 
			
		||||
        ProgressionTracker.Set(isTrackingController ? .25f : ProgressionTracker.Progression, $"Read state enable");
 | 
			
		||||
        return stateEnable;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public override void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
 | 
			
		||||
    {
 | 
			
		||||
        IStateEnable stateEnable = (IStateEnable)value!;
 | 
			
		||||
 | 
			
		||||
        bool isTrackingController = ProgressionTracker.Progression.ApproximatelyEquals(0f);
 | 
			
		||||
        ProgressionTracker.Set(isTrackingController ? .25f : ProgressionTracker.Progression, $"Serializing state enable");
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new MappingStart());
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new Scalar(nameof(IStateEnable.Enabled)));
 | 
			
		||||
        emitter.Emit(new Scalar(stateEnable.Enabled.ToString()));
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new Scalar(SERIALIZED_SCALAR_NAME));
 | 
			
		||||
        serializer(new SerializedClass(stateEnable));
 | 
			
		||||
 | 
			
		||||
        ProgressionTracker.Set(isTrackingController ? 1f : ProgressionTracker.Progression, $"Serialized state enable");
 | 
			
		||||
        emitter.Emit(new MappingEnd());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,46 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core.Serialization;
 | 
			
		||||
using Syntriax.Engine.Core.Factory;
 | 
			
		||||
 | 
			
		||||
using YamlDotNet.Core;
 | 
			
		||||
using YamlDotNet.Core.Events;
 | 
			
		||||
using YamlDotNet.Serialization;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Serializers.Yaml;
 | 
			
		||||
 | 
			
		||||
public class TypeContainerConverter : EngineTypeYamlSerializerBase<TypeContainer>
 | 
			
		||||
{
 | 
			
		||||
    public override TypeContainer Read(IParser parser, Type type, ObjectDeserializer rootDeserializer)
 | 
			
		||||
    {
 | 
			
		||||
        parser.Consume<MappingStart>();
 | 
			
		||||
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(nameof(TypeContainer.Type)) != 0)
 | 
			
		||||
            throw new ArgumentException($"{nameof(TypeContainer)} mapping must start with {nameof(TypeContainer.Type)}");
 | 
			
		||||
        string typeFullName = parser.Consume<Scalar>().Value;
 | 
			
		||||
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(nameof(TypeContainer.Value)) != 0)
 | 
			
		||||
            throw new ArgumentException($"{nameof(TypeContainer)} mapping must end with {nameof(TypeContainer.Type)}");
 | 
			
		||||
 | 
			
		||||
        object? value = rootDeserializer(TypeFactory.GetType(typeFullName));
 | 
			
		||||
 | 
			
		||||
        parser.Consume<MappingEnd>();
 | 
			
		||||
 | 
			
		||||
        return new TypeContainer() { Type = typeFullName, Value = value };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public override void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
 | 
			
		||||
    {
 | 
			
		||||
        TypeContainer? typeContainer = (TypeContainer)value!;
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new MappingStart());
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new Scalar(nameof(TypeContainer.Type)));
 | 
			
		||||
        emitter.Emit(new Scalar(typeContainer.Type));
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new Scalar(nameof(TypeContainer.Value)));
 | 
			
		||||
        serializer(typeContainer.Value, TypeFactory.GetType(typeContainer.Type));
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new MappingEnd());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,94 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Serialization;
 | 
			
		||||
 | 
			
		||||
using YamlDotNet.Core;
 | 
			
		||||
using YamlDotNet.Core.Events;
 | 
			
		||||
using YamlDotNet.Serialization;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Serializers.Yaml;
 | 
			
		||||
 | 
			
		||||
public class UniverseConverter : EngineTypeYamlSerializerBase<IUniverse>
 | 
			
		||||
{
 | 
			
		||||
    public override IUniverse? Read(IParser parser, Type type, ObjectDeserializer rootDeserializer)
 | 
			
		||||
    {
 | 
			
		||||
        bool isTrackingController = ProgressionTracker.Progression.ApproximatelyEquals(0f);
 | 
			
		||||
        ProgressionTracker.Set(isTrackingController ? 0.1f : ProgressionTracker.Progression, "Reading universe");
 | 
			
		||||
 | 
			
		||||
        string id;
 | 
			
		||||
 | 
			
		||||
        IUniverse universe;
 | 
			
		||||
        IStateEnable stateEnable;
 | 
			
		||||
        List<IUniverseObject> universeObjects;
 | 
			
		||||
 | 
			
		||||
        parser.Consume<MappingStart>();
 | 
			
		||||
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(nameof(IUniverse.Id)) != 0)
 | 
			
		||||
            throw new();
 | 
			
		||||
        id = parser.Consume<Scalar>().Value;
 | 
			
		||||
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(SERIALIZED_SCALAR_NAME) != 0)
 | 
			
		||||
            throw new();
 | 
			
		||||
        SerializedClass instanceSerializedClass = (SerializedClass)rootDeserializer(typeof(SerializedClass))!;
 | 
			
		||||
        ProgressionTracker.Set(isTrackingController ? .2f : ProgressionTracker.Progression, $"Creating {instanceSerializedClass.Type}");
 | 
			
		||||
        universe = (IUniverse)instanceSerializedClass.CreateInstance(EntityRegistry);
 | 
			
		||||
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(nameof(IUniverse.StateEnable)) != 0)
 | 
			
		||||
            throw new();
 | 
			
		||||
        stateEnable = (IStateEnable)rootDeserializer(typeof(IStateEnable))!;
 | 
			
		||||
 | 
			
		||||
        ProgressionTracker.Set(isTrackingController ? .5f : ProgressionTracker.Progression, $"Reading universe objects");
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(nameof(IUniverse.UniverseObjects)) != 0)
 | 
			
		||||
            throw new();
 | 
			
		||||
        universeObjects = (List<IUniverseObject>)rootDeserializer(typeof(List<IUniverseObject>))!;
 | 
			
		||||
 | 
			
		||||
        parser.Consume<MappingEnd>();
 | 
			
		||||
 | 
			
		||||
        universe.Id = id;
 | 
			
		||||
 | 
			
		||||
        stateEnable.Assign(universe);
 | 
			
		||||
        universe.Assign(stateEnable);
 | 
			
		||||
 | 
			
		||||
        ProgressionTracker.Set(isTrackingController ? .9f : ProgressionTracker.Progression, "Registering universe objects");
 | 
			
		||||
        for (int i = 0; i < universeObjects.Count; i++)
 | 
			
		||||
        {
 | 
			
		||||
            IUniverseObject uo = universeObjects[i];
 | 
			
		||||
            ProgressionTracker.Set(isTrackingController ? .9f + .1f * ((float)i / universeObjects.Count) : ProgressionTracker.Progression, $"Registering {uo.Name}");
 | 
			
		||||
 | 
			
		||||
            universe.Register(uo);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ProgressionTracker.Set(isTrackingController ? 1f : ProgressionTracker.Progression, $"Created {instanceSerializedClass.Type}");
 | 
			
		||||
        return universe;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public override void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
 | 
			
		||||
    {
 | 
			
		||||
        IUniverse universe = (IUniverse)value!;
 | 
			
		||||
 | 
			
		||||
        bool isTrackingController = ProgressionTracker.Progression.ApproximatelyEquals(0f);
 | 
			
		||||
        ProgressionTracker.Set(isTrackingController ? .25f : ProgressionTracker.Progression, $"Serializing universe");
 | 
			
		||||
 | 
			
		||||
        IEnumerable<IUniverseObject> rootUniverseObjects = universe.UniverseObjects.Where(uo => uo.Parent is null);
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new MappingStart());
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new Scalar(nameof(IUniverse.Id)));
 | 
			
		||||
        emitter.Emit(new Scalar(universe.Id));
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new Scalar(SERIALIZED_SCALAR_NAME));
 | 
			
		||||
        serializer(new SerializedClass(universe));
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new Scalar(nameof(IUniverse.StateEnable)));
 | 
			
		||||
        serializer(universe.StateEnable);
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new Scalar(nameof(IUniverse.UniverseObjects)));
 | 
			
		||||
        serializer(rootUniverseObjects);
 | 
			
		||||
 | 
			
		||||
        ProgressionTracker.Set(isTrackingController ? 1f : ProgressionTracker.Progression, $"Serialized universe");
 | 
			
		||||
        emitter.Emit(new MappingEnd());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,105 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Serialization;
 | 
			
		||||
 | 
			
		||||
using YamlDotNet.Core;
 | 
			
		||||
using YamlDotNet.Core.Events;
 | 
			
		||||
using YamlDotNet.Serialization;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Serializers.Yaml;
 | 
			
		||||
 | 
			
		||||
public class UniverseObjectSerializer : EngineTypeYamlSerializerBase<IUniverseObject>
 | 
			
		||||
{
 | 
			
		||||
    public override IUniverseObject? Read(IParser parser, Type type, ObjectDeserializer rootDeserializer)
 | 
			
		||||
    {
 | 
			
		||||
        bool isTrackingController = ProgressionTracker.Progression.ApproximatelyEquals(0f);
 | 
			
		||||
 | 
			
		||||
        string name;
 | 
			
		||||
        string id;
 | 
			
		||||
 | 
			
		||||
        IUniverseObject universeObject;
 | 
			
		||||
        IStateEnable stateEnable;
 | 
			
		||||
        IBehaviourController behaviourController;
 | 
			
		||||
        List<IUniverseObject> children;
 | 
			
		||||
 | 
			
		||||
        parser.Consume<MappingStart>();
 | 
			
		||||
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(nameof(IUniverseObject.Name)) != 0)
 | 
			
		||||
            throw new();
 | 
			
		||||
        name = parser.Consume<Scalar>().Value;
 | 
			
		||||
        ProgressionTracker.Set(isTrackingController ? .1f : ProgressionTracker.Progression, $"Reading {name}");
 | 
			
		||||
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(nameof(IUniverseObject.Id)) != 0)
 | 
			
		||||
            throw new();
 | 
			
		||||
        id = parser.Consume<Scalar>().Value;
 | 
			
		||||
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(SERIALIZED_SCALAR_NAME) != 0)
 | 
			
		||||
            throw new();
 | 
			
		||||
        SerializedClass instanceSerializedClass = (SerializedClass)rootDeserializer(typeof(SerializedClass))!;
 | 
			
		||||
        ProgressionTracker.Set(isTrackingController ? .3f : ProgressionTracker.Progression, $"Creating {instanceSerializedClass.Type}");
 | 
			
		||||
        universeObject = (IUniverseObject)instanceSerializedClass.CreateInstance(EntityRegistry);
 | 
			
		||||
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(nameof(IUniverseObject.StateEnable)) != 0)
 | 
			
		||||
            throw new();
 | 
			
		||||
        stateEnable = (IStateEnable)rootDeserializer(typeof(IStateEnable))!;
 | 
			
		||||
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(nameof(IUniverseObject.BehaviourController)) != 0)
 | 
			
		||||
            throw new();
 | 
			
		||||
        behaviourController = (IBehaviourController)rootDeserializer(typeof(IBehaviourController))!;
 | 
			
		||||
 | 
			
		||||
        if (parser.Consume<Scalar>().Value.CompareTo(nameof(IUniverseObject.Children)) != 0)
 | 
			
		||||
            throw new();
 | 
			
		||||
        children = (List<IUniverseObject>)rootDeserializer(typeof(List<IUniverseObject>))!;
 | 
			
		||||
 | 
			
		||||
        parser.Consume<MappingEnd>();
 | 
			
		||||
 | 
			
		||||
        universeObject.Id = id;
 | 
			
		||||
        universeObject.Name = name;
 | 
			
		||||
 | 
			
		||||
        stateEnable.Assign(universeObject);
 | 
			
		||||
        universeObject.Assign(stateEnable);
 | 
			
		||||
 | 
			
		||||
        behaviourController.Assign(universeObject);
 | 
			
		||||
        universeObject.Assign(behaviourController);
 | 
			
		||||
 | 
			
		||||
        foreach (IUniverseObject child in children)
 | 
			
		||||
            universeObject.AddChild(child);
 | 
			
		||||
 | 
			
		||||
        ProgressionTracker.Set(isTrackingController ? .3f : ProgressionTracker.Progression, $"Created {name}");
 | 
			
		||||
        return universeObject;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public override void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
 | 
			
		||||
    {
 | 
			
		||||
        IUniverseObject universeObject = (IUniverseObject)value!;
 | 
			
		||||
 | 
			
		||||
        bool isTrackingController = ProgressionTracker.Progression.ApproximatelyEquals(0f);
 | 
			
		||||
        ProgressionTracker.Set(isTrackingController ? .25f : ProgressionTracker.Progression, $"Serializing universe object");
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new MappingStart());
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new Scalar(nameof(IUniverseObject.Name)));
 | 
			
		||||
        emitter.Emit(new Scalar(universeObject.Name));
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new Scalar(nameof(IUniverseObject.Id)));
 | 
			
		||||
        emitter.Emit(new Scalar(universeObject.Id));
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new Scalar(SERIALIZED_SCALAR_NAME));
 | 
			
		||||
        serializer(new SerializedClass(universeObject));
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new Scalar(nameof(IUniverseObject.StateEnable)));
 | 
			
		||||
        serializer(universeObject.StateEnable);
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new Scalar(nameof(IUniverseObject.BehaviourController)));
 | 
			
		||||
        serializer(universeObject.BehaviourController);
 | 
			
		||||
 | 
			
		||||
        emitter.Emit(new Scalar(nameof(IUniverseObject.Children)));
 | 
			
		||||
        serializer(universeObject.Children.Where(c => !c.GetType().HasAttribute<IgnoreSerializationAttribute>()));
 | 
			
		||||
 | 
			
		||||
        ProgressionTracker.Set(isTrackingController ? 1f : ProgressionTracker.Progression, $"Serializing universe object");
 | 
			
		||||
        emitter.Emit(new MappingEnd());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,15 @@
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
			
		||||
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <TargetFramework>net9.0</TargetFramework>
 | 
			
		||||
    <ImplicitUsings>disable</ImplicitUsings>
 | 
			
		||||
    <Nullable>enable</Nullable>
 | 
			
		||||
    <RootNamespace>Syntriax.Engine.Serializers.Yaml</RootNamespace>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <ProjectReference Include="..\..\Engine\Engine.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\YamlDotNet\YamlDotNet\YamlDotNet.csproj" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
</Project>
 | 
			
		||||
@@ -0,0 +1,6 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Serializers.Yaml;
 | 
			
		||||
 | 
			
		||||
[Serializable]
 | 
			
		||||
public class SerializerInProgressException() : Exception("There's already a running deserialization in progress.");
 | 
			
		||||
							
								
								
									
										142
									
								
								Engine.Serializers/Engine.Serializers.Yaml/YamlSerializer.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								Engine.Serializers/Engine.Serializers.Yaml/YamlSerializer.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,142 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Serialization;
 | 
			
		||||
 | 
			
		||||
using YamlDotNet.Serialization;
 | 
			
		||||
using YamlDotNet.Serialization.NamingConventions;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Serializers.Yaml;
 | 
			
		||||
 | 
			
		||||
public class YamlSerializer : Core.Serialization.ISerializer
 | 
			
		||||
{
 | 
			
		||||
    private readonly YamlDotNet.Serialization.ISerializer serializer = null!;
 | 
			
		||||
    private readonly YamlDotNet.Serialization.IDeserializer deserializer = null!;
 | 
			
		||||
 | 
			
		||||
    private readonly EntityRegistry entityRegistry = null!;
 | 
			
		||||
    private readonly IProgressionTracker progressionTracker = null!;
 | 
			
		||||
 | 
			
		||||
    private readonly System.Threading.Lock Lock = new();
 | 
			
		||||
 | 
			
		||||
    public YamlSerializer()
 | 
			
		||||
    {
 | 
			
		||||
        entityRegistry = new();
 | 
			
		||||
        progressionTracker = new ProgressionTracker();
 | 
			
		||||
 | 
			
		||||
        SerializerBuilder serializerBuilder = new SerializerBuilder()
 | 
			
		||||
                .WithNamingConvention(PascalCaseNamingConvention.Instance)
 | 
			
		||||
                .DisableAliases();
 | 
			
		||||
 | 
			
		||||
        DeserializerBuilder deserializerBuilder = new DeserializerBuilder()
 | 
			
		||||
                .WithNamingConvention(PascalCaseNamingConvention.Instance);
 | 
			
		||||
 | 
			
		||||
        foreach (IEngineTypeYamlConverter typeConverter in GetEngineYamlTypeConverters())
 | 
			
		||||
        {
 | 
			
		||||
            typeConverter.Serializer = this;
 | 
			
		||||
            typeConverter.EntityRegistry = entityRegistry;
 | 
			
		||||
            typeConverter.ProgressionTracker = progressionTracker;
 | 
			
		||||
 | 
			
		||||
            deserializerBuilder = deserializerBuilder.WithTypeConverter(typeConverter);
 | 
			
		||||
            serializerBuilder = serializerBuilder.WithTypeConverter(typeConverter);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        serializer = serializerBuilder.Build();
 | 
			
		||||
        deserializer = deserializerBuilder.Build();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static IEnumerable<IEngineTypeYamlConverter> GetEngineYamlTypeConverters()
 | 
			
		||||
    {
 | 
			
		||||
        foreach (Type type in Assembly.GetExecutingAssembly().GetTypes().Where(t => typeof(IEngineTypeYamlConverter).IsAssignableFrom(t) && t.IsClass && !t.IsAbstract))
 | 
			
		||||
            yield return (Activator.CreateInstance(type) as IEngineTypeYamlConverter)!;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public string Serialize(object instance)
 | 
			
		||||
    {
 | 
			
		||||
        lock (Lock)
 | 
			
		||||
        {
 | 
			
		||||
            return serializer.Serialize(instance);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public object Deserialize(string configuration)
 | 
			
		||||
    {
 | 
			
		||||
        lock (Lock)
 | 
			
		||||
        {
 | 
			
		||||
            entityRegistry.Reset();
 | 
			
		||||
            object result = deserializer.Deserialize(configuration)!;
 | 
			
		||||
            entityRegistry.AssignAll();
 | 
			
		||||
            return result;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public object Deserialize(string configuration, Type type)
 | 
			
		||||
    {
 | 
			
		||||
        lock (Lock)
 | 
			
		||||
        {
 | 
			
		||||
            entityRegistry.Reset();
 | 
			
		||||
            object result = deserializer.Deserialize(configuration, type)!;
 | 
			
		||||
            entityRegistry.AssignAll();
 | 
			
		||||
            return result;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public T Deserialize<T>(string configuration)
 | 
			
		||||
    {
 | 
			
		||||
        lock (Lock)
 | 
			
		||||
        {
 | 
			
		||||
            entityRegistry.Reset();
 | 
			
		||||
            T result = deserializer.Deserialize<T>(configuration);
 | 
			
		||||
            entityRegistry.AssignAll();
 | 
			
		||||
            return result;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ProgressiveTask<object> DeserializeAsync(string configuration)
 | 
			
		||||
    {
 | 
			
		||||
        lock (Lock)
 | 
			
		||||
        {
 | 
			
		||||
            progressionTracker.Reset();
 | 
			
		||||
            Task<object> task = Task.Run(() => Deserialize(configuration));
 | 
			
		||||
            return new ProgressiveTask<object>(progressionTracker, task);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ProgressiveTask<object> DeserializeAsync(string configuration, Type type)
 | 
			
		||||
    {
 | 
			
		||||
        lock (Lock)
 | 
			
		||||
        {
 | 
			
		||||
            progressionTracker.Reset();
 | 
			
		||||
            Task<object> task = Task.Run(() => Deserialize(configuration, type));
 | 
			
		||||
            return new ProgressiveTask<object>(progressionTracker, task);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ProgressiveTask<T> DeserializeAsync<T>(string configuration)
 | 
			
		||||
    {
 | 
			
		||||
        lock (Lock)
 | 
			
		||||
        {
 | 
			
		||||
            progressionTracker.Reset();
 | 
			
		||||
            Task<T> task = Task.Run(() => Deserialize<T>(configuration));
 | 
			
		||||
            return new ProgressiveTask<T>(progressionTracker, task);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ProgressiveTask<string> SerializeAsync(object instance)
 | 
			
		||||
    {
 | 
			
		||||
        lock (Lock)
 | 
			
		||||
        {
 | 
			
		||||
            progressionTracker.Reset();
 | 
			
		||||
            Task<string> task = Task.Run(() => Serialize(instance));
 | 
			
		||||
            return new ProgressiveTask<string>(progressionTracker, task);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    internal object InternalDeserialize(string configuration, Type type)
 | 
			
		||||
    {
 | 
			
		||||
        return deserializer.Deserialize(configuration, type)!;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1
									
								
								Engine.Serializers/YamlDotNet
									
									
									
									
									
										Submodule
									
								
							
							
								
								
								
								
								
							
						
						
									
										1
									
								
								Engine.Serializers/YamlDotNet
									
									
									
									
									
										Submodule
									
								
							 Submodule Engine.Serializers/YamlDotNet added at 62048d7abe
									
								
							@@ -1,8 +1,8 @@
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
			
		||||
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <TargetFramework>net8.0</TargetFramework>
 | 
			
		||||
    <ImplicitUsings>enable</ImplicitUsings>
 | 
			
		||||
    <TargetFramework>net9.0</TargetFramework>
 | 
			
		||||
    <ImplicitUsings>disable</ImplicitUsings>
 | 
			
		||||
    <Nullable>enable</Nullable>
 | 
			
		||||
    <RootNamespace>Syntriax.Engine.Systems</RootNamespace>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								Engine.Systems/Preserver.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								Engine.Systems/Preserver.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
namespace Syntriax.Engine.Systems
 | 
			
		||||
{
 | 
			
		||||
    // 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.
 | 
			
		||||
    // I will hopefully one day fix it and remove this.
 | 
			
		||||
    public static class Preserver
 | 
			
		||||
    {
 | 
			
		||||
        public static void Preserve() { }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,14 +1,14 @@
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Systems.StateMachine;
 | 
			
		||||
 | 
			
		||||
public interface IState
 | 
			
		||||
public interface IState : IEntity, INameable
 | 
			
		||||
{
 | 
			
		||||
    event StateUpdateEventHandler? OnStateUpdate;
 | 
			
		||||
    event StateTransitionedFromEventHandler? OnStateTransitionedFrom;
 | 
			
		||||
    event StateTransitionedToEventHandler? OnStateTransitionedTo;
 | 
			
		||||
    event StateTransitionReadyEventHandler? OnStateTransitionReady;
 | 
			
		||||
 | 
			
		||||
    string Name { get; }
 | 
			
		||||
 | 
			
		||||
    IState? GetNextState();
 | 
			
		||||
 | 
			
		||||
    void Update();
 | 
			
		||||
 
 | 
			
		||||
@@ -1,20 +1,36 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Systems.StateMachine;
 | 
			
		||||
 | 
			
		||||
public class State : IState
 | 
			
		||||
public class State : BaseEntity, IState
 | 
			
		||||
{
 | 
			
		||||
    public event IState.StateUpdateEventHandler? OnStateUpdate = null;
 | 
			
		||||
    public event IState.StateTransitionedFromEventHandler? OnStateTransitionedFrom = null;
 | 
			
		||||
    public event IState.StateTransitionedToEventHandler? OnStateTransitionedTo = null;
 | 
			
		||||
    public event IState.StateTransitionReadyEventHandler? OnStateTransitionReady = null;
 | 
			
		||||
    public event INameable.NameChangedEventHandler? OnNameChanged = null;
 | 
			
		||||
 | 
			
		||||
    private readonly List<StateTransition> transitions = [];
 | 
			
		||||
    private readonly Dictionary<string, StateTransition> possibleTransitions = [];
 | 
			
		||||
    private string _name = "Default State Name";
 | 
			
		||||
 | 
			
		||||
    public string Name { get; set; } = "Default State Name";
 | 
			
		||||
    public IReadOnlyList<StateTransition> Transitions => transitions;
 | 
			
		||||
    public IReadOnlyDictionary<string, StateTransition> PossibleTransitions => possibleTransitions;
 | 
			
		||||
    public string Name
 | 
			
		||||
    {
 | 
			
		||||
        get => _name;
 | 
			
		||||
        set
 | 
			
		||||
        {
 | 
			
		||||
            if (_name.CompareTo(value) == 0)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            string previousName = _name;
 | 
			
		||||
            _name = value;
 | 
			
		||||
            OnNameChanged?.Invoke(this, previousName);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void RemoveTransition(string name)
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -7,10 +7,24 @@ public abstract class StateBehaviourBase : Behaviour, IState
 | 
			
		||||
    public event IState.StateUpdateEventHandler? OnStateUpdate = null;
 | 
			
		||||
    public event IState.StateTransitionedFromEventHandler? OnStateTransitionedFrom = null;
 | 
			
		||||
    public event IState.StateTransitionedToEventHandler? OnStateTransitionedTo = null;
 | 
			
		||||
    public event INameable.NameChangedEventHandler? OnNameChanged = null;
 | 
			
		||||
 | 
			
		||||
    public abstract event IState.StateTransitionReadyEventHandler? OnStateTransitionReady;
 | 
			
		||||
 | 
			
		||||
    public abstract string Name { get; }
 | 
			
		||||
    private string _name = string.Empty;
 | 
			
		||||
    public string Name
 | 
			
		||||
    {
 | 
			
		||||
        get => _name;
 | 
			
		||||
        set
 | 
			
		||||
        {
 | 
			
		||||
            if (_name.CompareTo(value) == 0)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            string previousName = _name;
 | 
			
		||||
            _name = value;
 | 
			
		||||
            OnNameChanged?.Invoke(this, previousName);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected virtual void OnUpdateState() { }
 | 
			
		||||
    public void Update()
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Serialization;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Systems.StateMachine;
 | 
			
		||||
 | 
			
		||||
@@ -7,6 +8,7 @@ public class StateMachine : Behaviour
 | 
			
		||||
    public event StateChangedEventHandler? OnStateChanged = null;
 | 
			
		||||
 | 
			
		||||
    private IState _state = new State();
 | 
			
		||||
    [Serialize]
 | 
			
		||||
    public IState State
 | 
			
		||||
    {
 | 
			
		||||
        get => _state;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,7 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Systems.StateMachine;
 | 
			
		||||
 | 
			
		||||
public readonly record struct StateTransition(IState State, IReadOnlyList<Func<bool>> Conditions)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,7 @@
 | 
			
		||||
// Reference: https://easings.net
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Systems.Tween;
 | 
			
		||||
 | 
			
		||||
internal static class EaseConstants
 | 
			
		||||
@@ -7,52 +9,54 @@ internal static class EaseConstants
 | 
			
		||||
    internal const float c1 = 1.70158f;
 | 
			
		||||
    internal const float c2 = c1 * 1.525f;
 | 
			
		||||
    internal const float c3 = c1 + 1f;
 | 
			
		||||
    internal const float c4 = 2f * Core.Math.PI / 3f;
 | 
			
		||||
    internal const float c5 = 2f * Core.Math.PI / 4.5f;
 | 
			
		||||
    internal const float c4 = 2f * Math.PI / 3f;
 | 
			
		||||
    internal const float c5 = 2f * Math.PI / 4.5f;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public readonly struct EaseLinear : IEasing { public readonly float Evaluate(float x) => x; }
 | 
			
		||||
public abstract class EasingBase<T> where T : IEasing, new() { public static readonly T Instance = new(); }
 | 
			
		||||
 | 
			
		||||
public readonly struct EaseInQuad : IEasing { public readonly float Evaluate(float x) => x * x; }
 | 
			
		||||
public readonly struct EaseOutQuad : IEasing { public readonly float Evaluate(float x) => 1f - (1f - x) * (1f - x); }
 | 
			
		||||
public readonly struct EaseInOutQuad : IEasing { public readonly float Evaluate(float x) => x < .5f ? 2f * x * x : 1f - Core.Math.Pow(-2f * x + 2f, 2f) * .5f; }
 | 
			
		||||
public class EaseLinear : EasingBase<EaseLinear>, IEasing { public float Evaluate(float x) => x; }
 | 
			
		||||
 | 
			
		||||
public readonly struct EaseInCubic : IEasing { public readonly float Evaluate(float x) => x * x * x; }
 | 
			
		||||
public readonly struct EaseOutCubic : IEasing { public readonly float Evaluate(float x) => 1f - Core.Math.Pow(1f - x, 3f); }
 | 
			
		||||
public readonly struct EaseInOutCubic : IEasing { public readonly float Evaluate(float x) => x < .5f ? 4f * x * x * x : 1f - Core.Math.Pow(-2f * x + 2f, 3f) * .5f; }
 | 
			
		||||
public class EaseInQuad : EasingBase<EaseInQuad>, IEasing { public float Evaluate(float x) => x * x; }
 | 
			
		||||
public class EaseOutQuad : EasingBase<EaseOutQuad>, IEasing { public float Evaluate(float x) => 1f - (1f - x) * (1f - x); }
 | 
			
		||||
public class EaseInOutQuad : EasingBase<EaseInOutQuad>, IEasing { public float Evaluate(float x) => x < .5f ? 2f * x * x : 1f - Math.Pow(-2f * x + 2f, 2f) * .5f; }
 | 
			
		||||
 | 
			
		||||
public readonly struct EaseInQuart : IEasing { public readonly float Evaluate(float x) => x * x * x * x; }
 | 
			
		||||
public readonly struct EaseOutQuart : IEasing { public readonly float Evaluate(float x) => 1f - Core.Math.Pow(1f - x, 4f); }
 | 
			
		||||
public readonly struct EaseInOutQuart : IEasing { public readonly float Evaluate(float x) => x < .5f ? 8f * x * x * x * x : 1f - Core.Math.Pow(-2f * x + 2f, 4f) * .5f; }
 | 
			
		||||
public class EaseInCubic : EasingBase<EaseInCubic>, IEasing { public float Evaluate(float x) => x * x * x; }
 | 
			
		||||
public class EaseOutCubic : EasingBase<EaseOutCubic>, IEasing { public float Evaluate(float x) => 1f - Math.Pow(1f - x, 3f); }
 | 
			
		||||
public class EaseInOutCubic : EasingBase<EaseInOutCubic>, IEasing { public float Evaluate(float x) => x < .5f ? 4f * x * x * x : 1f - Math.Pow(-2f * x + 2f, 3f) * .5f; }
 | 
			
		||||
 | 
			
		||||
public readonly struct EaseInQuint : IEasing { public readonly float Evaluate(float x) => x * x * x * x * x; }
 | 
			
		||||
public readonly struct EaseOutQuint : IEasing { public readonly float Evaluate(float x) => 1f - Core.Math.Pow(1f - x, 5f); }
 | 
			
		||||
public readonly struct EaseInOutQuint : IEasing { public readonly float Evaluate(float x) => x < .5f ? 16f * x * x * x * x * x : 1f - Core.Math.Pow(-2f * x + 2f, 5f) * .5f; }
 | 
			
		||||
public class EaseInQuart : EasingBase<EaseInQuart>, IEasing { public float Evaluate(float x) => x * x * x * x; }
 | 
			
		||||
public class EaseOutQuart : EasingBase<EaseOutQuart>, IEasing { public float Evaluate(float x) => 1f - Math.Pow(1f - x, 4f); }
 | 
			
		||||
public class EaseInOutQuart : EasingBase<EaseInOutQuart>, IEasing { public float Evaluate(float x) => x < .5f ? 8f * x * x * x * x : 1f - Math.Pow(-2f * x + 2f, 4f) * .5f; }
 | 
			
		||||
 | 
			
		||||
public readonly struct EaseInSine : IEasing { public readonly float Evaluate(float x) => 1f - Core.Math.Cos(x * Core.Math.PI * .5f); }
 | 
			
		||||
public readonly struct EaseOutSine : IEasing { public readonly float Evaluate(float x) => Core.Math.Sin(x * Core.Math.PI * .5f); }
 | 
			
		||||
public readonly struct EaseInOutSine : IEasing { public readonly float Evaluate(float x) => -(Core.Math.Cos(Core.Math.PI * x) - 1f) * .5f; }
 | 
			
		||||
public class EaseInQuint : EasingBase<EaseInQuint>, IEasing { public float Evaluate(float x) => x * x * x * x * x; }
 | 
			
		||||
public class EaseOutQuint : EasingBase<EaseOutQuint>, IEasing { public float Evaluate(float x) => 1f - Math.Pow(1f - x, 5f); }
 | 
			
		||||
public class EaseInOutQuint : EasingBase<EaseInOutQuint>, IEasing { public float Evaluate(float x) => x < .5f ? 16f * x * x * x * x * x : 1f - Math.Pow(-2f * x + 2f, 5f) * .5f; }
 | 
			
		||||
 | 
			
		||||
public readonly struct EaseInExpo : IEasing { public readonly float Evaluate(float x) => x == 0f ? 0f : Core.Math.Pow(2f, 10f * x - 10f); }
 | 
			
		||||
public readonly struct EaseOutExpo : IEasing { public readonly float Evaluate(float x) => x == 1f ? 1f : 1f - Core.Math.Pow(2f, -10f * x); }
 | 
			
		||||
public readonly struct EaseInOutExpo : IEasing { public readonly float Evaluate(float x) => x == 0f ? 0f : x == 1f ? 1f : x < .5f ? Core.Math.Pow(2f, 20f * x - 10f) * .5f : (2f - Core.Math.Pow(2f, -20f * x + 10f)) * .5f; }
 | 
			
		||||
public class EaseInSine : EasingBase<EaseInSine>, IEasing { public float Evaluate(float x) => 1f - Math.Cos(x * Math.PI * .5f); }
 | 
			
		||||
public class EaseOutSine : EasingBase<EaseOutSine>, IEasing { public float Evaluate(float x) => Math.Sin(x * Math.PI * .5f); }
 | 
			
		||||
public class EaseInOutSine : EasingBase<EaseInOutSine>, IEasing { public float Evaluate(float x) => -(Math.Cos(Math.PI * x) - 1f) * .5f; }
 | 
			
		||||
 | 
			
		||||
public readonly struct EaseInCirc : IEasing { public readonly float Evaluate(float x) => 1f - Core.Math.Sqrt(1f - Core.Math.Pow(x, 2f)); }
 | 
			
		||||
public readonly struct EaseOutCirc : IEasing { public readonly float Evaluate(float x) => Core.Math.Sqrt(1f - Core.Math.Pow(x - 1f, 2f)); }
 | 
			
		||||
public readonly struct EaseInOutCirc : IEasing { public readonly float Evaluate(float x) => x < .5f ? (1f - Core.Math.Sqrt(1f - Core.Math.Pow(2f * x, 2f))) * .5f : (Core.Math.Sqrt(1f - Core.Math.Pow(-2f * x + 2f, 2f)) + 1f) * .5f; }
 | 
			
		||||
public class EaseInExpo : EasingBase<EaseInExpo>, IEasing { public float Evaluate(float x) => x == 0f ? 0f : Math.Pow(2f, 10f * x - 10f); }
 | 
			
		||||
public class EaseOutExpo : EasingBase<EaseOutExpo>, IEasing { public float Evaluate(float x) => x == 1f ? 1f : 1f - Math.Pow(2f, -10f * x); }
 | 
			
		||||
public class EaseInOutExpo : EasingBase<EaseInOutExpo>, IEasing { public float Evaluate(float x) => x == 0f ? 0f : x == 1f ? 1f : x < .5f ? Math.Pow(2f, 20f * x - 10f) * .5f : (2f - Math.Pow(2f, -20f * x + 10f)) * .5f; }
 | 
			
		||||
 | 
			
		||||
public readonly struct EaseInBack : IEasing { public readonly float Evaluate(float x) => EaseConstants.c3 * x * x * x - EaseConstants.c1 * x * x; }
 | 
			
		||||
public readonly struct EaseOutBack : IEasing { public readonly float Evaluate(float x) => 1f + EaseConstants.c3 * Core.Math.Pow(x - 1f, 3f) + EaseConstants.c1 * Core.Math.Pow(x - 1f, 2f); }
 | 
			
		||||
public readonly struct EaseInOutBack : IEasing { public readonly float Evaluate(float x) => x < .5f ? Core.Math.Pow(2f * x, 2f) * ((EaseConstants.c2 + 1f) * 2f * x - EaseConstants.c2) * .5f : (Core.Math.Pow(2f * x - 2f, 2f) * ((EaseConstants.c2 + 1f) * (x * 2f - 2f) + EaseConstants.c2) + 2f) * .5f; }
 | 
			
		||||
public class EaseInCirc : EasingBase<EaseInCirc>, IEasing { public float Evaluate(float x) => 1f - Math.Sqrt(1f - Math.Pow(x, 2f)); }
 | 
			
		||||
public class EaseOutCirc : EasingBase<EaseOutCirc>, IEasing { public float Evaluate(float x) => Math.Sqrt(1f - Math.Pow(x - 1f, 2f)); }
 | 
			
		||||
public class EaseInOutCirc : EasingBase<EaseInOutCirc>, IEasing { public float Evaluate(float x) => x < .5f ? (1f - Math.Sqrt(1f - Math.Pow(2f * x, 2f))) * .5f : (Math.Sqrt(1f - Math.Pow(-2f * x + 2f, 2f)) + 1f) * .5f; }
 | 
			
		||||
 | 
			
		||||
public readonly struct EaseInElastic : IEasing { public readonly float Evaluate(float x) => x == 0 ? 0 : x == 1f ? 1f : -Core.Math.Pow(2f, 10f * x - 10f) * Core.Math.Sin((x * 10f - 10.75f) * EaseConstants.c4); }
 | 
			
		||||
public readonly struct EaseOutElastic : IEasing { public readonly float Evaluate(float x) => x == 0 ? 0 : x == 1f ? 1f : Core.Math.Pow(2f, -10f * x) * Core.Math.Sin((x * 10f - .75f) * EaseConstants.c4) + 1f; }
 | 
			
		||||
public readonly struct EaseInOutElastic : IEasing { public readonly float Evaluate(float x) => x == 0 ? 0 : x == 1f ? 1f : x < .5f ? -(Core.Math.Pow(2f, 20f * x - 10f) * Core.Math.Sin((20f * x - 11.125f) * EaseConstants.c5)) * .5f : Core.Math.Pow(2f, -20f * x + 10f) * Core.Math.Sin((20f * x - 11.125f) * EaseConstants.c5) * .5f + 1f; }
 | 
			
		||||
public class EaseInBack : EasingBase<EaseInBack>, IEasing { public float Evaluate(float x) => EaseConstants.c3 * x * x * x - EaseConstants.c1 * x * x; }
 | 
			
		||||
public class EaseOutBack : EasingBase<EaseOutBack>, IEasing { public float Evaluate(float x) => 1f + EaseConstants.c3 * Math.Pow(x - 1f, 3f) + EaseConstants.c1 * Math.Pow(x - 1f, 2f); }
 | 
			
		||||
public class EaseInOutBack : EasingBase<EaseInOutBack>, IEasing { public float Evaluate(float x) => x < .5f ? Math.Pow(2f * x, 2f) * ((EaseConstants.c2 + 1f) * 2f * x - EaseConstants.c2) * .5f : (Math.Pow(2f * x - 2f, 2f) * ((EaseConstants.c2 + 1f) * (x * 2f - 2f) + EaseConstants.c2) + 2f) * .5f; }
 | 
			
		||||
 | 
			
		||||
public readonly struct EaseInBounce : IEasing { public readonly float Evaluate(float x) => 1f - new EaseOutBounce().Evaluate(1f - x); }
 | 
			
		||||
public readonly struct EaseOutBounce : IEasing
 | 
			
		||||
public class EaseInElastic : EasingBase<EaseInElastic>, IEasing { public float Evaluate(float x) => x == 0 ? 0 : x == 1f ? 1f : -Math.Pow(2f, 10f * x - 10f) * Math.Sin((x * 10f - 10.75f) * EaseConstants.c4); }
 | 
			
		||||
public class EaseOutElastic : EasingBase<EaseOutElastic>, IEasing { public float Evaluate(float x) => x == 0 ? 0 : x == 1f ? 1f : Math.Pow(2f, -10f * x) * Math.Sin((x * 10f - .75f) * EaseConstants.c4) + 1f; }
 | 
			
		||||
public class EaseInOutElastic : EasingBase<EaseInOutElastic>, IEasing { public float Evaluate(float x) => x == 0 ? 0 : x == 1f ? 1f : x < .5f ? -(Math.Pow(2f, 20f * x - 10f) * Math.Sin((20f * x - 11.125f) * EaseConstants.c5)) * .5f : Math.Pow(2f, -20f * x + 10f) * Math.Sin((20f * x - 11.125f) * EaseConstants.c5) * .5f + 1f; }
 | 
			
		||||
 | 
			
		||||
public class EaseInBounce : EasingBase<EaseInBounce>, IEasing { public float Evaluate(float x) => 1f - EaseOutBounce.Instance.Evaluate(1f - x); }
 | 
			
		||||
public class EaseOutBounce : EasingBase<EaseOutBounce>, IEasing
 | 
			
		||||
{
 | 
			
		||||
    public readonly float Evaluate(float x)
 | 
			
		||||
    public float Evaluate(float x)
 | 
			
		||||
    {
 | 
			
		||||
        const float n1 = 7.5625f;
 | 
			
		||||
        const float d1 = 2.75f;
 | 
			
		||||
@@ -69,4 +73,4 @@ public readonly struct EaseOutBounce : IEasing
 | 
			
		||||
        return n1 * (x -= 2.625f / d1) * x + .984375f;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
public readonly struct EaseInOutBounce : IEasing { public readonly float Evaluate(float x) => x < .5f ? (1f - new EaseOutBounce().Evaluate(1f - 2f * x)) * .5f : (1f + new EaseOutBounce().Evaluate(2f * x - 1f)) * .5f; }
 | 
			
		||||
public class EaseInOutBounce : IEasing { public float Evaluate(float x) => x < .5f ? (1f - EaseOutBounce.Instance.Evaluate(1f - 2f * x)) * .5f : (1f + EaseOutBounce.Instance.Evaluate(2f * x - 1f)) * .5f; }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								Engine.Systems/Tween/EngineExtensions/TweenAABBExtensions.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								Engine.Systems/Tween/EngineExtensions/TweenAABBExtensions.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Systems.Tween;
 | 
			
		||||
 | 
			
		||||
public static class TweenAABBExtensions
 | 
			
		||||
{
 | 
			
		||||
    public static ITween TweenAABB(this AABB initialAABB, ITweenManager tweenManager, float duration, AABB targetAABB, Action<AABB> setMethod)
 | 
			
		||||
        => tweenManager.StartTween(duration, t => setMethod?.InvokeSafe(new AABB(initialAABB.LowerBoundary.Lerp(targetAABB.LowerBoundary, t), initialAABB.UpperBoundary.Lerp(targetAABB.UpperBoundary, t))));
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,12 @@
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Systems.Tween;
 | 
			
		||||
 | 
			
		||||
public static class TweenCamera2DExtensions
 | 
			
		||||
{
 | 
			
		||||
    public static ITween TweenZoom(this ICamera2D camera2D, ITweenManager tweenManager, float duration, float targetZoom)
 | 
			
		||||
    {
 | 
			
		||||
        float initialZoom = camera2D.Zoom;
 | 
			
		||||
        return tweenManager.StartTween(duration, t => camera2D.Zoom = initialZoom.Lerp(targetZoom, t));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,16 @@
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Systems.Tween;
 | 
			
		||||
 | 
			
		||||
public static class TweenCircleExtensions
 | 
			
		||||
{
 | 
			
		||||
    public static ITween TweenCircle(this Circle initialCircle, ITweenManager tweenManager, float duration, Circle targetCircle, System.Action<Circle> setMethod)
 | 
			
		||||
        => tweenManager.StartTween(duration,
 | 
			
		||||
            t => setMethod?.InvokeSafe(
 | 
			
		||||
                new Circle(
 | 
			
		||||
                    initialCircle.Center.Lerp(targetCircle.Center, t),
 | 
			
		||||
                    initialCircle.Diameter.Lerp(targetCircle.Diameter, t)
 | 
			
		||||
                )
 | 
			
		||||
            )
 | 
			
		||||
        );
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,15 @@
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Systems.Tween;
 | 
			
		||||
 | 
			
		||||
public static class TweenColorExtensions
 | 
			
		||||
{
 | 
			
		||||
    public static ITween TweenColor(this ColorRGB initialColorRGB, ITweenManager tweenManager, float duration, ColorRGB targetColorRGB, System.Action<ColorRGB> setMethod)
 | 
			
		||||
        => tweenManager.StartTween(duration, t => setMethod?.InvokeSafe(initialColorRGB.Lerp(targetColorRGB, t)));
 | 
			
		||||
 | 
			
		||||
    public static ITween TweenColor(this ColorRGBA initialColorRGBA, ITweenManager tweenManager, float duration, ColorRGBA targetColorRGBA, System.Action<ColorRGBA> setMethod)
 | 
			
		||||
        => tweenManager.StartTween(duration, t => setMethod?.InvokeSafe(initialColorRGBA.Lerp(targetColorRGBA, t)));
 | 
			
		||||
 | 
			
		||||
    public static ITween TweenColor(this ColorHSV initialColorHSV, ITweenManager tweenManager, float duration, ColorHSV targetColorHSV, System.Action<ColorHSV> setMethod)
 | 
			
		||||
        => tweenManager.StartTween(duration, t => setMethod?.InvokeSafe(initialColorHSV.Lerp(targetColorHSV, t)));
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,16 @@
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Systems.Tween;
 | 
			
		||||
 | 
			
		||||
public static class TweenLine2DEquationExtensions
 | 
			
		||||
{
 | 
			
		||||
    public static ITween TweenLine2DEquation(this Line2DEquation initialLine2DEquation, ITweenManager tweenManager, float duration, Line2DEquation targetLine2DEquation, System.Action<Line2DEquation> setMethod)
 | 
			
		||||
        => tweenManager.StartTween(duration,
 | 
			
		||||
            t => setMethod?.InvokeSafe(
 | 
			
		||||
                new Line2DEquation(
 | 
			
		||||
                    initialLine2DEquation.Slope.Lerp(targetLine2DEquation.Slope, t),
 | 
			
		||||
                    initialLine2DEquation.OffsetY.Lerp(targetLine2DEquation.OffsetY, t)
 | 
			
		||||
                )
 | 
			
		||||
            )
 | 
			
		||||
        );
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,16 @@
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Systems.Tween;
 | 
			
		||||
 | 
			
		||||
public static class TweenLine2DExtensions
 | 
			
		||||
{
 | 
			
		||||
    public static ITween TweenLine2D(this Line2D initialLine2D, ITweenManager tweenManager, float duration, Line2D targetLine2D, System.Action<Line2D> setMethod)
 | 
			
		||||
        => tweenManager.StartTween(duration,
 | 
			
		||||
            t => setMethod?.InvokeSafe(
 | 
			
		||||
                new Line2D(
 | 
			
		||||
                    initialLine2D.From.Lerp(targetLine2D.From, t),
 | 
			
		||||
                    initialLine2D.To.Lerp(targetLine2D.To, t)
 | 
			
		||||
                )
 | 
			
		||||
            )
 | 
			
		||||
        );
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,17 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Systems.Tween;
 | 
			
		||||
 | 
			
		||||
public static class TweenProjection1DExtensions
 | 
			
		||||
{
 | 
			
		||||
    public static ITween TweenProjection1D(this Projection1D initialProjection1D, ITweenManager tweenManager, float duration, Projection1D targetProjection1D, Action<Projection1D> setMethod)
 | 
			
		||||
        => tweenManager.StartTween(duration,
 | 
			
		||||
            t => setMethod?.InvokeSafe(
 | 
			
		||||
                new Projection1D(
 | 
			
		||||
                    initialProjection1D.Min.Lerp(targetProjection1D.Min, t),
 | 
			
		||||
                    initialProjection1D.Max.Lerp(targetProjection1D.Max, t)
 | 
			
		||||
                )
 | 
			
		||||
            )
 | 
			
		||||
        );
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,10 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Systems.Tween;
 | 
			
		||||
 | 
			
		||||
public static class TweenQuaternionExtensions
 | 
			
		||||
{
 | 
			
		||||
    public static ITween TweenQuaternion(this Quaternion initialQuaternion, ITweenManager tweenManager, float duration, Quaternion targetQuaternion, Action<Quaternion> setMethod)
 | 
			
		||||
       => tweenManager.StartTween(duration, t => setMethod?.InvokeSafe(initialQuaternion.SLerp(targetQuaternion, t)));
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,34 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Systems.Tween;
 | 
			
		||||
 | 
			
		||||
public static class TweenShape2DExtensions
 | 
			
		||||
{
 | 
			
		||||
    public static ITween TweenShape2D(this Shape2D shape, ITweenManager tweenManager, float duration, Shape2D targetShape2D)
 | 
			
		||||
    {
 | 
			
		||||
        List<Vector2D> initialVertices = new(shape.Vertices);
 | 
			
		||||
        List<Vector2D> shapeVertices = new(shape.Vertices);
 | 
			
		||||
 | 
			
		||||
        return tweenManager.StartTween(duration,
 | 
			
		||||
                t =>
 | 
			
		||||
                {
 | 
			
		||||
                    shapeVertices.Clear();
 | 
			
		||||
                    int maxCount = initialVertices.Count.Max(targetShape2D.Vertices.Count);
 | 
			
		||||
                    for (int i = 0; i < maxCount; i++)
 | 
			
		||||
                    {
 | 
			
		||||
                        int initialIndex = (i * (initialVertices.Count / (float)maxCount)).RoundToInt(Math.RoundMode.Floor);
 | 
			
		||||
                        int targetIndex = (i * (targetShape2D.Vertices.Count / (float)maxCount)).RoundToInt(Math.RoundMode.Floor);
 | 
			
		||||
                        shapeVertices.Add(targetShape2D.Vertices[targetIndex].Lerp(initialVertices[initialIndex], 1f - t));
 | 
			
		||||
                    }
 | 
			
		||||
                    shape.Vertices = shapeVertices;
 | 
			
		||||
                }
 | 
			
		||||
            ).OnComplete(() =>
 | 
			
		||||
            {
 | 
			
		||||
                shapeVertices.Clear();
 | 
			
		||||
                for (int i = 0; i < targetShape2D.Vertices.Count; i++)
 | 
			
		||||
                    shapeVertices.Add(targetShape2D.Vertices[i]);
 | 
			
		||||
                shape.Vertices = shapeVertices;
 | 
			
		||||
            });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,42 @@
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Systems.Tween;
 | 
			
		||||
 | 
			
		||||
public static class TweenTransform2DExtensions
 | 
			
		||||
{
 | 
			
		||||
    public static ITween TweenPosition(this ITransform2D transform2D, ITweenManager tweenManager, float duration, Vector2D targetPosition)
 | 
			
		||||
    {
 | 
			
		||||
        Vector2D initialPosition = transform2D.Position;
 | 
			
		||||
        return tweenManager.StartTween(duration, t => transform2D.Position = initialPosition.Lerp(targetPosition, t));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static ITween TweenScale(this ITransform2D transform2D, ITweenManager tweenManager, float duration, Vector2D targetScale)
 | 
			
		||||
    {
 | 
			
		||||
        Vector2D initialScale = transform2D.Scale;
 | 
			
		||||
        return tweenManager.StartTween(duration, t => transform2D.Scale = initialScale.Lerp(targetScale, t));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static ITween TweenRotation(this ITransform2D transform2D, ITweenManager tweenManager, float duration, float targetRotation)
 | 
			
		||||
    {
 | 
			
		||||
        float initialRotation = transform2D.Rotation;
 | 
			
		||||
        return tweenManager.StartTween(duration, t => transform2D.Rotation = initialRotation.Lerp(targetRotation, t));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static ITween TweenLocalPosition(this ITransform2D transform2D, ITweenManager tweenManager, float duration, Vector2D targetLocalPosition)
 | 
			
		||||
    {
 | 
			
		||||
        Vector2D initialLocalPosition = transform2D.LocalPosition;
 | 
			
		||||
        return tweenManager.StartTween(duration, t => transform2D.LocalPosition = initialLocalPosition.Lerp(targetLocalPosition, t));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static ITween TweenLocalScale(this ITransform2D transform2D, ITweenManager tweenManager, float duration, Vector2D targetLocalScale)
 | 
			
		||||
    {
 | 
			
		||||
        Vector2D initialLocalScale = transform2D.LocalScale;
 | 
			
		||||
        return tweenManager.StartTween(duration, t => transform2D.LocalScale = initialLocalScale.Lerp(targetLocalScale, t));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static ITween TweenLocalRotation(this ITransform2D transform2D, ITweenManager tweenManager, float duration, float targetLocalRotation)
 | 
			
		||||
    {
 | 
			
		||||
        float initialLocalRotation = transform2D.LocalRotation;
 | 
			
		||||
        return tweenManager.StartTween(duration, t => transform2D.LocalRotation = initialLocalRotation.Lerp(targetLocalRotation, t));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,18 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Systems.Tween;
 | 
			
		||||
 | 
			
		||||
public static class TweenTriangleExtensions
 | 
			
		||||
{
 | 
			
		||||
    public static ITween TweenTriangle(this Triangle initialTriangle, ITweenManager tweenManager, float duration, Triangle targetTriangle, Action<Triangle> setMethod)
 | 
			
		||||
       => tweenManager.StartTween(duration,
 | 
			
		||||
            t => setMethod?.InvokeSafe(
 | 
			
		||||
                new Triangle(
 | 
			
		||||
                    initialTriangle.A.Lerp(targetTriangle.A, t),
 | 
			
		||||
                    initialTriangle.B.Lerp(targetTriangle.B, t),
 | 
			
		||||
                    initialTriangle.C.Lerp(targetTriangle.C, t)
 | 
			
		||||
                )
 | 
			
		||||
            )
 | 
			
		||||
        );
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,9 @@
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Systems.Tween;
 | 
			
		||||
 | 
			
		||||
public static class TweenVector2DExtensions
 | 
			
		||||
{
 | 
			
		||||
    public static ITween TweenVector2D(this Vector2D initialVector2D, ITweenManager tweenManager, float duration, Vector2D targetVector2D, System.Action<Vector2D> setMethod)
 | 
			
		||||
        => tweenManager.StartTween(duration, t => setMethod?.InvokeSafe(initialVector2D.Lerp(targetVector2D, t)));
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,9 @@
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Systems.Tween;
 | 
			
		||||
 | 
			
		||||
public static class TweenVector3DExtensions
 | 
			
		||||
{
 | 
			
		||||
    public static ITween TweenVector3D(this Vector3D initialVector3D, ITweenManager tweenManager, float duration, Vector3D targetVector3D, System.Action<Vector3D> setMethod)
 | 
			
		||||
        => tweenManager.StartTween(duration, t => setMethod?.InvokeSafe(initialVector3D.Lerp(targetVector3D, t)));
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										9
									
								
								Engine.Systems/Tween/ITweenManager.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								Engine.Systems/Tween/ITweenManager.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
namespace Syntriax.Engine.Systems.Tween;
 | 
			
		||||
 | 
			
		||||
public interface ITweenManager
 | 
			
		||||
{
 | 
			
		||||
    ITween StartTween(float duration, TweenSetCallback? setCallback = null);
 | 
			
		||||
    void CancelTween(ITween tween);
 | 
			
		||||
 | 
			
		||||
    delegate void TweenSetCallback(float t);
 | 
			
		||||
}
 | 
			
		||||
@@ -43,7 +43,7 @@ internal class Tween : ITween
 | 
			
		||||
    public float Progress { get; internal set; } = 0f;
 | 
			
		||||
    private float _counter = 0f;
 | 
			
		||||
 | 
			
		||||
    public IEasing Easing { get; set; } = new EaseLinear();
 | 
			
		||||
    public IEasing Easing { get; set; } = EaseLinear.Instance;
 | 
			
		||||
    public float Value => Easing.Evaluate(Progress);
 | 
			
		||||
 | 
			
		||||
    public float Counter
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,5 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Systems.Tween;
 | 
			
		||||
@@ -47,42 +49,49 @@ public static class TweenExtensions
 | 
			
		||||
        tweenConcrete.OnStarted += _ => callback.InvokeSafe();
 | 
			
		||||
        return tween;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static ITween OnPause(this ITween tween, Action callback)
 | 
			
		||||
    {
 | 
			
		||||
        Tween tweenConcrete = (Tween)tween;
 | 
			
		||||
        tweenConcrete.OnPaused += _ => callback.InvokeSafe();
 | 
			
		||||
        return tween;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static ITween OnResume(this ITween tween, Action callback)
 | 
			
		||||
    {
 | 
			
		||||
        Tween tweenConcrete = (Tween)tween;
 | 
			
		||||
        tweenConcrete.OnResumed += _ => callback.InvokeSafe();
 | 
			
		||||
        return tween;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static ITween OnCancel(this ITween tween, Action callback)
 | 
			
		||||
    {
 | 
			
		||||
        Tween tweenConcrete = (Tween)tween;
 | 
			
		||||
        tweenConcrete.OnCancelled += _ => callback.InvokeSafe();
 | 
			
		||||
        return tween;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static ITween OnComplete(this ITween tween, Action callback)
 | 
			
		||||
    {
 | 
			
		||||
        Tween tweenConcrete = (Tween)tween;
 | 
			
		||||
        tweenConcrete.OnCompleted += _ => callback.InvokeSafe();
 | 
			
		||||
        return tween;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static ITween OnEnd(this ITween tween, Action callback)
 | 
			
		||||
    {
 | 
			
		||||
        Tween tweenConcrete = (Tween)tween;
 | 
			
		||||
        tweenConcrete.OnEnded += _ => callback.InvokeSafe();
 | 
			
		||||
        return tween;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static ITween OnUpdate(this ITween tween, Action callback)
 | 
			
		||||
    {
 | 
			
		||||
        Tween tweenConcrete = (Tween)tween;
 | 
			
		||||
        tweenConcrete.OnUpdated += _ => callback.InvokeSafe();
 | 
			
		||||
        return tween;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static ITween OnDeltaUpdate(this ITween tween, Action<float> callback)
 | 
			
		||||
    {
 | 
			
		||||
        Tween tweenConcrete = (Tween)tween;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,16 +1,17 @@
 | 
			
		||||
using System.Collections;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Systems.Tween;
 | 
			
		||||
 | 
			
		||||
public class TweenManager : UniverseObject
 | 
			
		||||
public class TweenManager : UniverseObject, ITweenManager
 | 
			
		||||
{
 | 
			
		||||
    private CoroutineManager coroutineManager = null!;
 | 
			
		||||
 | 
			
		||||
    private readonly Dictionary<ITween, IEnumerator> runningCoroutines = [];
 | 
			
		||||
 | 
			
		||||
    public ITween StartTween(float duration, TweenSetCallback? setCallback = null)
 | 
			
		||||
    public ITween StartTween(float duration, ITweenManager.TweenSetCallback? setCallback = null)
 | 
			
		||||
    {
 | 
			
		||||
        Tween tween = new(duration);
 | 
			
		||||
        tween.OnUpdated += tween => setCallback?.InvokeSafe(tween.Value);
 | 
			
		||||
@@ -60,6 +61,4 @@ public class TweenManager : UniverseObject
 | 
			
		||||
    {
 | 
			
		||||
        coroutineManager = null!;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public delegate void TweenSetCallback(float t);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										24
									
								
								Engine.sln
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								Engine.sln
									
									
									
									
									
								
							@@ -11,14 +11,17 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Systems", "Engine.Sy
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine", "Engine\Engine.csproj", "{58AE79C1-9203-44AE-8022-AA180F0A71DC}"
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Engine.Serializers", "Engine.Serializers", "{F88E129A-9A47-4D27-96EE-6EC02F79594B}"
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Serializers.Yaml", "Engine.Serializers\Engine.Serializers.Yaml\Engine.Serializers.Yaml.csproj", "{E9D1CDC3-5BFF-4C87-AFEB-6CE372709176}"
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YamlDotNet", "Engine.Serializers\YamlDotNet\YamlDotNet\YamlDotNet.csproj", "{3D852C92-BC14-4893-AEF2-50612DAFCD8F}"
 | 
			
		||||
EndProject
 | 
			
		||||
Global
 | 
			
		||||
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 | 
			
		||||
		Debug|Any CPU = Debug|Any CPU
 | 
			
		||||
		Release|Any CPU = Release|Any CPU
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
	GlobalSection(SolutionProperties) = preSolution
 | 
			
		||||
		HideSolutionNode = FALSE
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
 | 
			
		||||
		{71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
			
		||||
@@ -36,5 +39,20 @@ Global
 | 
			
		||||
		{58AE79C1-9203-44AE-8022-AA180F0A71DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
			
		||||
		{58AE79C1-9203-44AE-8022-AA180F0A71DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{58AE79C1-9203-44AE-8022-AA180F0A71DC}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
			
		||||
		{E9D1CDC3-5BFF-4C87-AFEB-6CE372709176}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{E9D1CDC3-5BFF-4C87-AFEB-6CE372709176}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
			
		||||
		{E9D1CDC3-5BFF-4C87-AFEB-6CE372709176}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{E9D1CDC3-5BFF-4C87-AFEB-6CE372709176}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
			
		||||
		{3D852C92-BC14-4893-AEF2-50612DAFCD8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{3D852C92-BC14-4893-AEF2-50612DAFCD8F}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
			
		||||
		{3D852C92-BC14-4893-AEF2-50612DAFCD8F}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{3D852C92-BC14-4893-AEF2-50612DAFCD8F}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
	GlobalSection(SolutionProperties) = preSolution
 | 
			
		||||
		HideSolutionNode = FALSE
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
	GlobalSection(NestedProjects) = preSolution
 | 
			
		||||
		{E9D1CDC3-5BFF-4C87-AFEB-6CE372709176} = {F88E129A-9A47-4D27-96EE-6EC02F79594B}
 | 
			
		||||
		{3D852C92-BC14-4893-AEF2-50612DAFCD8F} = {F88E129A-9A47-4D27-96EE-6EC02F79594B}
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
EndGlobal
 | 
			
		||||
 
 | 
			
		||||
@@ -1,15 +1,16 @@
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
			
		||||
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <TargetFramework>net8.0</TargetFramework>
 | 
			
		||||
    <ImplicitUsings>enable</ImplicitUsings>
 | 
			
		||||
    <TargetFramework>net9.0</TargetFramework>
 | 
			
		||||
    <ImplicitUsings>disable</ImplicitUsings>
 | 
			
		||||
    <Nullable>enable</Nullable>
 | 
			
		||||
    <RootNamespace>Syntriax.Engine</RootNamespace>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <ProjectReference Include="..\Engine.Core\Engine.Core.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\Engine.Systems\Engine.Systems.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\Engine.Physics2D\Engine.Physics2D.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\Engine.Systems\Engine.Systems.csproj" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
</Project>
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user