refactor!: Identifiable interface extracted from IEntity

This commit is contained in:
2025-10-26 22:34:50 +03:00
parent 30a07dd034
commit ac2e160abb
13 changed files with 94 additions and 88 deletions

View File

@@ -3,18 +3,4 @@ namespace Engine.Core;
/// <summary> /// <summary>
/// Represents a basic entity in the engine. /// Represents a basic entity in the engine.
/// </summary> /// </summary>
public interface IEntity : IInitializable, IHasStateEnable public interface IEntity : IInitializable, IIdentifiable, IHasStateEnable;
{
/// <summary>
/// Event triggered when the <see cref="Id"/> of the <see cref="IEntity"/> changes.
/// The string action parameter is the previous <see cref="Id"/> of the <see cref="IEntity"/>.
/// </summary>
Event<IEntity, IdChangedArguments> OnIdChanged { get; }
/// <summary>
/// The ID of the <see cref="IEntity"/>.
/// </summary>
string Id { get; set; }
readonly record struct IdChangedArguments(string PreviousId);
}

View File

@@ -0,0 +1,20 @@
namespace Engine.Core;
/// <summary>
/// Represents any instance in the engine with an id.
/// </summary>
public interface IIdentifiable
{
/// <summary>
/// Event triggered when the <see cref="Id"/> of the <see cref="IIdentifiable"/> changes.
/// The string action parameter is the previous <see cref="Id"/> of the <see cref="IIdentifiable"/>.
/// </summary>
Event<IIdentifiable, IdChangedArguments> OnIdChanged { get; }
/// <summary>
/// The ID of the <see cref="IIdentifiable"/>.
/// </summary>
string Id { get; set; }
readonly record struct IdChangedArguments(string PreviousId);
}

View File

@@ -4,7 +4,7 @@ namespace Engine.Core;
public abstract class BaseEntity : IEntity public abstract class BaseEntity : IEntity
{ {
public Event<IEntity, IEntity.IdChangedArguments> OnIdChanged { get; } = new(); public Event<IIdentifiable, IIdentifiable.IdChangedArguments> OnIdChanged { get; } = new();
public Event<IInitializable> OnInitialized { get; } = new(); public Event<IInitializable> OnInitialized { get; } = new();
public Event<IInitializable> OnFinalized { get; } = new(); public Event<IInitializable> OnFinalized { get; } = new();
public Event<IHasStateEnable> OnStateEnableAssigned { get; } = new(); public Event<IHasStateEnable> OnStateEnableAssigned { get; } = new();

View File

@@ -1,39 +0,0 @@
using System;
using System.Collections.Generic;
namespace Engine.Core.Serialization;
public class EntityRegistry
{
public Event<EntityRegistry, EntityRegisteredArguments> 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?.Invoke(this, new(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?.Invoke(registeredEntities[id]);
}
public void Reset()
{
assignCallbacks.Clear();
registeredEntities.Clear();
}
public readonly record struct EntityRegisteredArguments(IEntity Entity);
}

View File

@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
namespace Engine.Core.Serialization;
public class IdentifiableRegistry
{
public Event<IdentifiableRegistry, EntityRegisteredArguments> OnEntityRegistered = null!;
private readonly Dictionary<string, Action<IIdentifiable>?> assignCallbacks = [];
private readonly Dictionary<string, IIdentifiable> registeredEntities = [];
public IReadOnlyDictionary<string, IIdentifiable> RegisteredEntities => registeredEntities;
public void Add(IIdentifiable identifiable)
{
if (registeredEntities.TryAdd(identifiable.Id, identifiable))
OnEntityRegistered?.Invoke(this, new(identifiable));
}
public void QueueAssign(string id, Action<IIdentifiable> setMethod)
{
assignCallbacks.TryAdd(id, null);
assignCallbacks[id] = assignCallbacks[id] + setMethod;
}
public void AssignAll()
{
foreach ((string id, Action<IIdentifiable>? action) in assignCallbacks)
action?.Invoke(registeredEntities[id]);
}
public void Reset()
{
assignCallbacks.Clear();
registeredEntities.Clear();
}
public readonly record struct EntityRegisteredArguments(IIdentifiable Entity);
}

View File

@@ -43,8 +43,8 @@ public class SerializedClass
continue; continue;
object? value = privatePropertyInfo.GetValue(@class); object? value = privatePropertyInfo.GetValue(@class);
if (value is IEntity entity) if (value is IIdentifiable identifiable)
Private.Add(privatePropertyInfo.Name, entity.Id); Private.Add(privatePropertyInfo.Name, identifiable.Id);
else else
Private.Add(privatePropertyInfo.Name, value); Private.Add(privatePropertyInfo.Name, value);
} }
@@ -61,8 +61,8 @@ public class SerializedClass
continue; continue;
object? value = publicPropertyInfo.GetValue(@class); object? value = publicPropertyInfo.GetValue(@class);
if (value is IEntity entity) if (value is IIdentifiable identifiable)
Public.Add(publicPropertyInfo.Name, entity.Id); Public.Add(publicPropertyInfo.Name, identifiable.Id);
else else
Public.Add(publicPropertyInfo.Name, value); Public.Add(publicPropertyInfo.Name, value);
} }
@@ -76,8 +76,8 @@ public class SerializedClass
continue; continue;
object? value = privateFieldInfo.GetValue(@class); object? value = privateFieldInfo.GetValue(@class);
if (value is IEntity entity) if (value is IIdentifiable identifiable)
Private.Add(privateFieldInfo.Name, entity.Id); Private.Add(privateFieldInfo.Name, identifiable.Id);
else else
Private.Add(privateFieldInfo.Name, value); Private.Add(privateFieldInfo.Name, value);
} }
@@ -91,8 +91,8 @@ public class SerializedClass
continue; continue;
object? value = publicFieldInfo.GetValue(@class); object? value = publicFieldInfo.GetValue(@class);
if (value is IEntity entity) if (value is IIdentifiable identifiable)
Public.Add(publicFieldInfo.Name, entity.Id); Public.Add(publicFieldInfo.Name, identifiable.Id);
else else
Public.Add(publicFieldInfo.Name, value); Public.Add(publicFieldInfo.Name, value);
} }
@@ -112,36 +112,36 @@ public class SerializedClass
return instance; return instance;
} }
public object CreateInstance(EntityRegistry? entityRegistry) public object CreateInstance(IdentifiableRegistry? identifiableRegistry)
{ {
if (entityRegistry is null) if (identifiableRegistry is null)
return CreateInstance(); return CreateInstance();
Type type = TypeFactory.GetType(Type); Type type = TypeFactory.GetType(Type);
object instance = TypeFactory.Get(type); object instance = TypeFactory.Get(type);
foreach ((string key, object? value) in Private) foreach ((string key, object? value) in Private)
AssignVariable(key, type, instance, value, PRIVATE_BINDING_FLAGS, entityRegistry); AssignVariable(key, type, instance, value, PRIVATE_BINDING_FLAGS, identifiableRegistry);
foreach ((string key, object? value) in Public) foreach ((string key, object? value) in Public)
AssignVariable(key, type, instance, value, PUBLIC_BINDING_FLAGS, entityRegistry); AssignVariable(key, type, instance, value, PUBLIC_BINDING_FLAGS, identifiableRegistry);
return instance; return instance;
} }
private static void AssignVariable(string key, Type type, object instance, object? value, BindingFlags bindingFlags, EntityRegistry entityRegistry) private static void AssignVariable(string key, Type type, object instance, object? value, BindingFlags bindingFlags, IdentifiableRegistry identifiableRegistry)
{ {
if (type.GetField(key, bindingFlags) is FieldInfo fieldInfo) if (type.GetField(key, bindingFlags) is FieldInfo fieldInfo)
{ {
if (typeof(IEntity).IsAssignableFrom(fieldInfo.FieldType)) if (typeof(IIdentifiable).IsAssignableFrom(fieldInfo.FieldType))
entityRegistry.QueueAssign(value?.ToString() ?? "", (entity) => fieldInfo.SetValue(instance, entity)); identifiableRegistry.QueueAssign(value?.ToString() ?? "", (entity) => fieldInfo.SetValue(instance, entity));
else else
fieldInfo.SetValue(instance, value); fieldInfo.SetValue(instance, value);
} }
else if (type.GetProperty(key, bindingFlags) is PropertyInfo propertyInfo) else if (type.GetProperty(key, bindingFlags) is PropertyInfo propertyInfo)
{ {
if (typeof(IEntity).IsAssignableFrom(propertyInfo.PropertyType)) if (typeof(IIdentifiable).IsAssignableFrom(propertyInfo.PropertyType))
entityRegistry.QueueAssign(value?.ToString() ?? "", (entity) => propertyInfo.SetValue(instance, entity)); identifiableRegistry.QueueAssign(value?.ToString() ?? "", (entity) => propertyInfo.SetValue(instance, entity));
else else
propertyInfo.SetValue(instance, value); propertyInfo.SetValue(instance, value);
} }

View File

@@ -8,6 +8,6 @@ namespace Engine.Serializers.Yaml;
public interface IEngineTypeYamlConverter : IYamlTypeConverter public interface IEngineTypeYamlConverter : IYamlTypeConverter
{ {
YamlSerializer Serializer { get; set; } YamlSerializer Serializer { get; set; }
EntityRegistry EntityRegistry { get; set; } IdentifiableRegistry IdentifiableRegistry { get; set; }
IProgressionTracker ProgressionTracker { get; set; } IProgressionTracker ProgressionTracker { get; set; }
} }

View File

@@ -36,7 +36,7 @@ public class BehaviourControllerConverter : EngineTypeYamlSerializerBase<IBehavi
throw new(); throw new();
SerializedClass instanceSerializedClass = (SerializedClass)rootDeserializer(typeof(SerializedClass))!; SerializedClass instanceSerializedClass = (SerializedClass)rootDeserializer(typeof(SerializedClass))!;
ProgressionTracker.Set(isTrackingController ? .5f : ProgressionTracker.Progression, $"Creating {instanceSerializedClass.Type}"); ProgressionTracker.Set(isTrackingController ? .5f : ProgressionTracker.Progression, $"Creating {instanceSerializedClass.Type}");
behaviourController = (IBehaviourController)instanceSerializedClass.CreateInstance(EntityRegistry); behaviourController = (IBehaviourController)instanceSerializedClass.CreateInstance(IdentifiableRegistry);
string value = parser.Consume<Scalar>().Value; string value = parser.Consume<Scalar>().Value;
if (value.CompareTo(nameof(IBehaviourController.StateEnable)) != 0) if (value.CompareTo(nameof(IBehaviourController.StateEnable)) != 0)

View File

@@ -36,7 +36,7 @@ public class BehaviourConverter : EngineTypeYamlSerializerBase<IBehaviour>
throw new(); throw new();
SerializedClass instanceSerializedClass = (SerializedClass)rootDeserializer(typeof(SerializedClass))!; SerializedClass instanceSerializedClass = (SerializedClass)rootDeserializer(typeof(SerializedClass))!;
ProgressionTracker.Set(isTrackingController ? .5f : ProgressionTracker.Progression, $"Creating {instanceSerializedClass.Type}"); ProgressionTracker.Set(isTrackingController ? .5f : ProgressionTracker.Progression, $"Creating {instanceSerializedClass.Type}");
behaviour = (IBehaviour)instanceSerializedClass.CreateInstance(EntityRegistry); behaviour = (IBehaviour)instanceSerializedClass.CreateInstance(IdentifiableRegistry);
if (parser.Consume<Scalar>().Value.CompareTo(nameof(IBehaviour.StateEnable)) != 0) if (parser.Consume<Scalar>().Value.CompareTo(nameof(IBehaviour.StateEnable)) != 0)
throw new(); throw new();

View File

@@ -12,7 +12,7 @@ public abstract class EngineTypeYamlSerializerBase<T> : IEngineTypeYamlConverter
{ {
protected const string SERIALIZED_SCALAR_NAME = "Properties"; protected const string SERIALIZED_SCALAR_NAME = "Properties";
public EntityRegistry EntityRegistry { get; set; } = null!; public IdentifiableRegistry IdentifiableRegistry { get; set; } = null!;
public YamlSerializer Serializer { get; set; } = null!; public YamlSerializer Serializer { get; set; } = null!;
public IProgressionTracker ProgressionTracker { get; set; } = null!; public IProgressionTracker ProgressionTracker { get; set; } = null!;
@@ -24,7 +24,7 @@ public abstract class EngineTypeYamlSerializerBase<T> : IEngineTypeYamlConverter
T? result = Read(parser, type, rootDeserializer); T? result = Read(parser, type, rootDeserializer);
if (result is IEntity entity) if (result is IEntity entity)
EntityRegistry.Add(entity); IdentifiableRegistry.Add(entity);
return result; return result;
} }

View File

@@ -29,7 +29,7 @@ public class StateEnableConverter : EngineTypeYamlSerializerBase<IStateEnable>
if (parser.Consume<Scalar>().Value.CompareTo(SERIALIZED_SCALAR_NAME) != 0) if (parser.Consume<Scalar>().Value.CompareTo(SERIALIZED_SCALAR_NAME) != 0)
throw new(); throw new();
SerializedClass instanceSerializedClass = (SerializedClass)rootDeserializer(typeof(SerializedClass))!; SerializedClass instanceSerializedClass = (SerializedClass)rootDeserializer(typeof(SerializedClass))!;
stateEnable = (IStateEnable)instanceSerializedClass.CreateInstance(EntityRegistry); stateEnable = (IStateEnable)instanceSerializedClass.CreateInstance(IdentifiableRegistry);
parser.Consume<MappingEnd>(); parser.Consume<MappingEnd>();

View File

@@ -40,7 +40,7 @@ public class UniverseObjectSerializer : EngineTypeYamlSerializerBase<IUniverseOb
throw new(); throw new();
SerializedClass instanceSerializedClass = (SerializedClass)rootDeserializer(typeof(SerializedClass))!; SerializedClass instanceSerializedClass = (SerializedClass)rootDeserializer(typeof(SerializedClass))!;
ProgressionTracker.Set(isTrackingController ? .3f : ProgressionTracker.Progression, $"Creating {instanceSerializedClass.Type}"); ProgressionTracker.Set(isTrackingController ? .3f : ProgressionTracker.Progression, $"Creating {instanceSerializedClass.Type}");
universeObject = (IUniverseObject)instanceSerializedClass.CreateInstance(EntityRegistry); universeObject = (IUniverseObject)instanceSerializedClass.CreateInstance(IdentifiableRegistry);
if (parser.Consume<Scalar>().Value.CompareTo(nameof(IUniverseObject.StateEnable)) != 0) if (parser.Consume<Scalar>().Value.CompareTo(nameof(IUniverseObject.StateEnable)) != 0)
throw new(); throw new();

View File

@@ -17,14 +17,14 @@ public class YamlSerializer : Core.Serialization.ISerializer
private readonly YamlDotNet.Serialization.ISerializer serializer = null!; private readonly YamlDotNet.Serialization.ISerializer serializer = null!;
private readonly YamlDotNet.Serialization.IDeserializer deserializer = null!; private readonly YamlDotNet.Serialization.IDeserializer deserializer = null!;
private readonly EntityRegistry entityRegistry = null!; private readonly IdentifiableRegistry identifiableRegistry = null!;
private readonly IProgressionTracker progressionTracker = null!; private readonly IProgressionTracker progressionTracker = null!;
private readonly System.Threading.Lock Lock = new(); private readonly System.Threading.Lock Lock = new();
public YamlSerializer() public YamlSerializer()
{ {
entityRegistry = new(); identifiableRegistry = new();
progressionTracker = new ProgressionTracker(); progressionTracker = new ProgressionTracker();
SerializerBuilder serializerBuilder = new SerializerBuilder() SerializerBuilder serializerBuilder = new SerializerBuilder()
@@ -37,7 +37,7 @@ public class YamlSerializer : Core.Serialization.ISerializer
foreach (IEngineTypeYamlConverter typeConverter in GetEngineYamlTypeConverters()) foreach (IEngineTypeYamlConverter typeConverter in GetEngineYamlTypeConverters())
{ {
typeConverter.Serializer = this; typeConverter.Serializer = this;
typeConverter.EntityRegistry = entityRegistry; typeConverter.IdentifiableRegistry = identifiableRegistry;
typeConverter.ProgressionTracker = progressionTracker; typeConverter.ProgressionTracker = progressionTracker;
deserializerBuilder = deserializerBuilder.WithTypeConverter(typeConverter); deserializerBuilder = deserializerBuilder.WithTypeConverter(typeConverter);
@@ -66,9 +66,9 @@ public class YamlSerializer : Core.Serialization.ISerializer
{ {
lock (Lock) lock (Lock)
{ {
entityRegistry.Reset(); identifiableRegistry.Reset();
object result = deserializer.Deserialize(configuration)!; object result = deserializer.Deserialize(configuration)!;
entityRegistry.AssignAll(); identifiableRegistry.AssignAll();
return result; return result;
} }
} }
@@ -77,9 +77,9 @@ public class YamlSerializer : Core.Serialization.ISerializer
{ {
lock (Lock) lock (Lock)
{ {
entityRegistry.Reset(); identifiableRegistry.Reset();
object result = deserializer.Deserialize(configuration, type)!; object result = deserializer.Deserialize(configuration, type)!;
entityRegistry.AssignAll(); identifiableRegistry.AssignAll();
return result; return result;
} }
} }
@@ -88,9 +88,9 @@ public class YamlSerializer : Core.Serialization.ISerializer
{ {
lock (Lock) lock (Lock)
{ {
entityRegistry.Reset(); identifiableRegistry.Reset();
T result = deserializer.Deserialize<T>(configuration); T result = deserializer.Deserialize<T>(configuration);
entityRegistry.AssignAll(); identifiableRegistry.AssignAll();
return result; return result;
} }
} }