From 0708ba89cc7b3d74c2984df524bd066024bab13c Mon Sep 17 00:00:00 2001 From: Syntriax Date: Sat, 10 Feb 2024 17:10:02 +0300 Subject: [PATCH] wip: Serialization 2 --- .../BehaviourControllerYamlConverter.cs | 53 +++++++++++++++++++ .../BehaviourDTOListConverter.cs | 41 ++++++++++++++ .../BehaviourYamlConverter.cs | 8 +-- .../DTOs/BehaviourControllerDTO.cs | 8 +++ Engine.Serialization/DTOs/BehaviourDTO.cs | 2 +- Engine.Serialization/DTOs/GameObjectDTO.cs | 5 +- Engine.Serialization/DTOs/StateEnableDto.cs | 2 +- Engine.Serialization/DTOs/TransformDTO.cs | 1 + .../GameObjectYamlConverter.cs | 12 +++-- Engine.Serialization/InternalExtensions.cs | 10 ++-- Engine.Serialization/Serialization.cs | 27 ++++++++++ .../StateEnableYamlConverter.cs | 8 +-- .../TransformYamlConverter.cs | 2 + 13 files changed, 158 insertions(+), 21 deletions(-) create mode 100644 Engine.Serialization/BehaviourControllerYamlConverter.cs create mode 100644 Engine.Serialization/BehaviourDTOListConverter.cs create mode 100644 Engine.Serialization/DTOs/BehaviourControllerDTO.cs create mode 100644 Engine.Serialization/Serialization.cs diff --git a/Engine.Serialization/BehaviourControllerYamlConverter.cs b/Engine.Serialization/BehaviourControllerYamlConverter.cs new file mode 100644 index 0000000..5af4c76 --- /dev/null +++ b/Engine.Serialization/BehaviourControllerYamlConverter.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using Engine.Serialization.DTOs; + +using YamlDotNet.Core; +using YamlDotNet.Core.Events; +using YamlDotNet.Serialization; + +namespace Engine.Serialization; + +internal class BehaviourControllerYamlConverter : IYamlTypeConverter +{ + public bool Accepts(Type type) => type == typeof(BehaviourControllerDTO); + + public object ReadYaml(IParser parser, Type type) + { + if (parser.Current is not MappingStart) + throw new InvalidOperationException("Expected MappingStart"); + + parser.MoveNext(); + var behaviourController = new BehaviourControllerDTO(); + while (parser.Current != null && parser.Current is not MappingEnd) + { + var propertyName = ((Scalar)parser.Current).Value; + parser.MoveNext(); + switch (propertyName) + { + case nameof(BehaviourControllerDTO.ClassType): + behaviourController.ClassType = ((Scalar)parser.Current).Value; + break; + case nameof(BehaviourControllerDTO.Behaviours): + behaviourController.Behaviours = (List)new BehaviourDTOListConverter().ReadYaml(parser, typeof(List)); + break; + } + parser.MoveNext(); + } + return behaviourController; + } + + public void WriteYaml(IEmitter emitter, object? value, Type type) + { + var behaviourController = (BehaviourControllerDTO)(value ?? throw new Exception()); + + BehaviourDTOListConverter behaviourDTOListConverter = new(); + + emitter.Emit(new MappingStart()); + emitter.Emit(new Scalar(nameof(BehaviourControllerDTO.ClassType))); + emitter.Emit(new Scalar(behaviourController.ClassType)); + emitter.Emit(new Scalar(nameof(BehaviourControllerDTO.Behaviours))); + behaviourDTOListConverter.WriteYaml(emitter, behaviourController.Behaviours, typeof(List)); + emitter.Emit(new MappingEnd()); + } +} diff --git a/Engine.Serialization/BehaviourDTOListConverter.cs b/Engine.Serialization/BehaviourDTOListConverter.cs new file mode 100644 index 0000000..4732154 --- /dev/null +++ b/Engine.Serialization/BehaviourDTOListConverter.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using Engine.Serialization.DTOs; + +using YamlDotNet.Core; +using YamlDotNet.Core.Events; +using YamlDotNet.Serialization; + +namespace Engine.Serialization; + +public class BehaviourDTOListConverter : IYamlTypeConverter +{ + public bool Accepts(Type type) + { + return type == typeof(List); + } + + public object ReadYaml(IParser parser, Type type) + { + var behaviours = new List(); + if (parser.Current is SequenceStart) + { + parser.MoveNext(); + while (parser.Current != null && !(parser.Current is SequenceEnd)) + { + behaviours.Add((BehaviourDTO)new BehaviourYamlConverter().ReadYaml(parser, typeof(BehaviourDTO))); + parser.MoveNext(); + } + } + return behaviours; + } + + public void WriteYaml(IEmitter emitter, object? value, Type type) + { + var behaviours = (List)(value ?? throw new Exception()); + emitter.Emit(new SequenceStart(null, null, false, SequenceStyle.Block)); + foreach (var behaviour in behaviours) + new BehaviourYamlConverter().WriteYaml(emitter, behaviour, typeof(BehaviourDTO)); + emitter.Emit(new SequenceEnd()); + } +} diff --git a/Engine.Serialization/BehaviourYamlConverter.cs b/Engine.Serialization/BehaviourYamlConverter.cs index 3fdc7fd..b8b7342 100644 --- a/Engine.Serialization/BehaviourYamlConverter.cs +++ b/Engine.Serialization/BehaviourYamlConverter.cs @@ -25,8 +25,8 @@ internal class BehaviourYamlConverter : IYamlTypeConverter parser.MoveNext(); switch (propertyName) { - case nameof(BehaviourDTO.ClassName): - behaviour.ClassName = ((Scalar)parser.Current).Value; + case nameof(BehaviourDTO.ClassType): + behaviour.ClassType = ((Scalar)parser.Current).Value; break; case nameof(BehaviourDTO.Priority): behaviour.Priority = int.Parse(((Scalar)parser.Current).Value); @@ -48,8 +48,8 @@ internal class BehaviourYamlConverter : IYamlTypeConverter emitter.Emit(new MappingStart()); - emitter.Emit(new Scalar(nameof(BehaviourDTO.ClassName))); - emitter.Emit(new Scalar(behaviour.ClassName.ToString())); + emitter.Emit(new Scalar(nameof(BehaviourDTO.ClassType))); + emitter.Emit(new Scalar(behaviour.ClassType.ToString())); emitter.Emit(new Scalar(nameof(BehaviourDTO.Priority))); emitter.Emit(new Scalar(behaviour.Priority.ToString())); diff --git a/Engine.Serialization/DTOs/BehaviourControllerDTO.cs b/Engine.Serialization/DTOs/BehaviourControllerDTO.cs new file mode 100644 index 0000000..310f300 --- /dev/null +++ b/Engine.Serialization/DTOs/BehaviourControllerDTO.cs @@ -0,0 +1,8 @@ +using System.Collections.Generic; + +namespace Engine.Serialization.DTOs; + +internal record struct BehaviourControllerDTO( + string ClassType, + List Behaviours +); diff --git a/Engine.Serialization/DTOs/BehaviourDTO.cs b/Engine.Serialization/DTOs/BehaviourDTO.cs index e988cfa..d8eed55 100644 --- a/Engine.Serialization/DTOs/BehaviourDTO.cs +++ b/Engine.Serialization/DTOs/BehaviourDTO.cs @@ -1,7 +1,7 @@ namespace Engine.Serialization.DTOs; internal record struct BehaviourDTO( - string ClassName, + string ClassType, int Priority, StateEnableDTO StateEnable ); diff --git a/Engine.Serialization/DTOs/GameObjectDTO.cs b/Engine.Serialization/DTOs/GameObjectDTO.cs index 951d566..e307fae 100644 --- a/Engine.Serialization/DTOs/GameObjectDTO.cs +++ b/Engine.Serialization/DTOs/GameObjectDTO.cs @@ -1,11 +1,10 @@ -using System.Collections.Generic; - namespace Engine.Serialization.DTOs; internal record struct GameObjectDTO( + string ClassType, string Id, string Name, TransformDTO Transform, - List Behaviours, + BehaviourControllerDTO BehaviourController, StateEnableDTO StateEnable ); diff --git a/Engine.Serialization/DTOs/StateEnableDto.cs b/Engine.Serialization/DTOs/StateEnableDto.cs index 9293d7f..4b2194f 100644 --- a/Engine.Serialization/DTOs/StateEnableDto.cs +++ b/Engine.Serialization/DTOs/StateEnableDto.cs @@ -1,6 +1,6 @@ namespace Engine.Serialization.DTOs; internal record struct StateEnableDTO( - string ClassName, + string ClassType, bool Enabled ); diff --git a/Engine.Serialization/DTOs/TransformDTO.cs b/Engine.Serialization/DTOs/TransformDTO.cs index f0b88bb..4fc5eef 100644 --- a/Engine.Serialization/DTOs/TransformDTO.cs +++ b/Engine.Serialization/DTOs/TransformDTO.cs @@ -3,6 +3,7 @@ using Syntriax.Engine.Core; namespace Engine.Serialization.DTOs; internal record struct TransformDTO( + string ClassType, string? ParentId, Vector2D Position, Vector2D Scale, diff --git a/Engine.Serialization/GameObjectYamlConverter.cs b/Engine.Serialization/GameObjectYamlConverter.cs index a13eec9..0b41264 100644 --- a/Engine.Serialization/GameObjectYamlConverter.cs +++ b/Engine.Serialization/GameObjectYamlConverter.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using Engine.Serialization.DTOs; @@ -51,20 +52,23 @@ internal class GameObjectYamlConverter : IYamlTypeConverter { var gameObject = (GameObjectDTO)(value ?? throw new Exception()); - Vector2DYamlConverter vector2DYamlConverter = new(); + TransformYamlConverter transformYamlConverter = new(); StateEnableYamlConverter stateEnableYamlConverter = new(); + BehaviourControllerYamlConverter behaviourControllerYamlConverter = new(); emitter.Emit(new MappingStart()); emitter.Emit(new Scalar(nameof(GameObjectDTO.Id))); emitter.Emit(new Scalar(gameObject.Id.ToString())); + emitter.Emit(new Scalar(nameof(GameObjectDTO.ClassType))); + emitter.Emit(new Scalar(gameObject.ClassType)); emitter.Emit(new Scalar(nameof(GameObjectDTO.Name))); emitter.Emit(new Scalar(gameObject.Name.ToString())); emitter.Emit(new Scalar(nameof(GameObjectDTO.Transform))); - vector2DYamlConverter.WriteYaml(emitter, gameObject.Transform, typeof(TransformDTO)); - // emitter.Emit(new Scalar(nameof(GameObjectDTO.Behaviours))); - // vector2DYamlConverter.WriteYaml(emitter, gameObject.Behaviours, typeof(BehavioursDTO)); + transformYamlConverter.WriteYaml(emitter, gameObject.Transform, typeof(TransformDTO)); emitter.Emit(new Scalar(nameof(GameObjectDTO.StateEnable))); stateEnableYamlConverter.WriteYaml(emitter, gameObject.StateEnable, typeof(StateEnableDTO)); + emitter.Emit(new Scalar(nameof(GameObjectDTO.BehaviourController))); + behaviourControllerYamlConverter.WriteYaml(emitter, gameObject.BehaviourController, typeof(BehaviourControllerDTO)); emitter.Emit(new MappingEnd()); } } diff --git a/Engine.Serialization/InternalExtensions.cs b/Engine.Serialization/InternalExtensions.cs index 0f5b8b5..c8653c1 100644 --- a/Engine.Serialization/InternalExtensions.cs +++ b/Engine.Serialization/InternalExtensions.cs @@ -7,19 +7,21 @@ namespace Engine.Serialization; internal static class InternalExtensions { public static TransformDTO ToDTO(this ITransform transform) - => new(transform.Parent?.GameObject.Id, transform.Position, transform.Scale, transform.Rotation); + => new(transform.GetType().FullName ?? throw new System.Exception(), transform.Parent?.GameObject.Id, transform.Position, transform.Scale, transform.Rotation); public static GameObjectDTO ToDTO(this IGameObject gameObject) - => new(gameObject.Id, gameObject.Name, gameObject.Transform.ToDTO(), gameObject.BehaviourController.ToDTO(), gameObject.StateEnable.ToDTO()); + => new(gameObject.GetType().FullName ?? throw new System.Exception(), gameObject.Id, gameObject.Name, gameObject.Transform.ToDTO(), gameObject.BehaviourController.ToDTO(), gameObject.StateEnable.ToDTO()); public static StateEnableDTO ToDTO(this IStateEnable stateEnable) => new(stateEnable.GetType().FullName ?? throw new System.Exception(), stateEnable.Enabled); - public static List ToDTO(this IBehaviourController behaviourController) + public static BehaviourControllerDTO ToDTO(this IBehaviourController behaviourController) { List dtos = []; foreach (var behaviour in behaviourController) dtos.Add(new(behaviour.GetType().FullName ?? throw new System.Exception(), behaviour.Priority, behaviour.StateEnable.ToDTO())); - return dtos; + return new(behaviourController.GetType().FullName ?? throw new System.Exception(), dtos); } + public static BehaviourDTO ToDTO(this IBehaviour behaviour) + => new(behaviour.GetType().FullName ?? throw new System.Exception(), behaviour.Priority, behaviour.StateEnable.ToDTO()); } diff --git a/Engine.Serialization/Serialization.cs b/Engine.Serialization/Serialization.cs new file mode 100644 index 0000000..6ae6026 --- /dev/null +++ b/Engine.Serialization/Serialization.cs @@ -0,0 +1,27 @@ +using System; +using Engine.Serialization.DTOs; +using Syntriax.Engine.Core; +using Syntriax.Engine.Core.Abstract; +using Syntriax.Engine.Core.Factory; + +namespace Engine.Serialization; + +public static class Serialization +{ + private static readonly ISerializer defaultSerializer = new YamlSerializer(); + + public static string SerializeGameObject(IGameObject gameObject) => Serialize(gameObject.ToDTO(), defaultSerializer); + public static T DeserializeGameObject(string serializedString) where T : class, IGameObject + { + GameObjectDTO gameObjectDTO = Deserialize(serializedString, defaultSerializer); + Type gameObjectType = (gameObjectDTO.ClassType is not null) ? TypeFactory.Get(gameObjectDTO.ClassType) : typeof(GameObject); + T t = new GameObjectFactory().Instantiate(gameObjectType); + return t; + } + + public static string Serialize(T @object) => Serialize(@object, defaultSerializer); + public static string Serialize(T @object, ISerializer serializer) => serializer.Serialize(@object); + + public static T Deserialize(string serializedString) => Deserialize(serializedString, defaultSerializer); + public static T Deserialize(string serializedString, ISerializer serializer) => serializer.Deserialize(serializedString); +} diff --git a/Engine.Serialization/StateEnableYamlConverter.cs b/Engine.Serialization/StateEnableYamlConverter.cs index e281d45..4cfcf4c 100644 --- a/Engine.Serialization/StateEnableYamlConverter.cs +++ b/Engine.Serialization/StateEnableYamlConverter.cs @@ -26,8 +26,8 @@ internal class StateEnableYamlConverter : IYamlTypeConverter parser.MoveNext(); switch (propertyName) { - case nameof(StateEnableDTO.ClassName): - stateEnable.ClassName = ((Scalar)parser.Current).Value; + case nameof(StateEnableDTO.ClassType): + stateEnable.ClassType = ((Scalar)parser.Current).Value; break; case nameof(StateEnableDTO.Enabled): stateEnable.Enabled = bool.Parse(((Scalar)parser.Current).Value); @@ -43,8 +43,8 @@ internal class StateEnableYamlConverter : IYamlTypeConverter var stateEnable = (StateEnableDTO)(value ?? throw new Exception()); emitter.Emit(new MappingStart()); - emitter.Emit(new Scalar(nameof(StateEnableDTO.ClassName))); - emitter.Emit(new Scalar(stateEnable.ClassName)); + emitter.Emit(new Scalar(nameof(StateEnableDTO.ClassType))); + emitter.Emit(new Scalar(stateEnable.ClassType)); emitter.Emit(new Scalar(nameof(StateEnableDTO.Enabled))); emitter.Emit(new Scalar(stateEnable.Enabled.ToString())); emitter.Emit(new MappingEnd()); diff --git a/Engine.Serialization/TransformYamlConverter.cs b/Engine.Serialization/TransformYamlConverter.cs index 1dccd7c..a6a774f 100644 --- a/Engine.Serialization/TransformYamlConverter.cs +++ b/Engine.Serialization/TransformYamlConverter.cs @@ -58,6 +58,8 @@ internal class TransformYamlConverter : IYamlTypeConverter emitter.Emit(new Scalar(nameof(TransformDTO.ParentId))); emitter.Emit(new Scalar(transform.ParentId)); } + emitter.Emit(new Scalar(nameof(TransformDTO.ClassType))); + emitter.Emit(new Scalar(transform.ClassType)); emitter.Emit(new Scalar(nameof(TransformDTO.Position))); vector2DYamlConverter.WriteYaml(emitter, transform.Position, typeof(Vector2D)); emitter.Emit(new Scalar(nameof(TransformDTO.Scale)));