From 4c04e3d02fcd62158818aec4874c4e260742b62c Mon Sep 17 00:00:00 2001 From: Syntriax Date: Sat, 10 Feb 2024 20:02:38 +0300 Subject: [PATCH] wip: Serialization Game Manager --- Engine.Serialization/DTOs/GameManagerDTO.cs | 8 +++ .../GameManagerYamlConverter.cs | 53 +++++++++++++++++++ .../GameObjectDTOListConverter.cs | 41 ++++++++++++++ Engine.Serialization/InternalExtensions.cs | 9 ++++ Engine.Serialization/Serialization.cs | 36 ++++++++++++- Engine.Serialization/YamlSerializer.cs | 24 ++++++--- 6 files changed, 162 insertions(+), 9 deletions(-) create mode 100644 Engine.Serialization/DTOs/GameManagerDTO.cs create mode 100644 Engine.Serialization/GameManagerYamlConverter.cs create mode 100644 Engine.Serialization/GameObjectDTOListConverter.cs diff --git a/Engine.Serialization/DTOs/GameManagerDTO.cs b/Engine.Serialization/DTOs/GameManagerDTO.cs new file mode 100644 index 0000000..00024ee --- /dev/null +++ b/Engine.Serialization/DTOs/GameManagerDTO.cs @@ -0,0 +1,8 @@ +using System.Collections.Generic; + +namespace Engine.Serialization.DTOs; + +internal record struct GameManagerDTO( + string ClassType, + List GameObjects +); diff --git a/Engine.Serialization/GameManagerYamlConverter.cs b/Engine.Serialization/GameManagerYamlConverter.cs new file mode 100644 index 0000000..36f8ffd --- /dev/null +++ b/Engine.Serialization/GameManagerYamlConverter.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 GameManagerYamlConverter : IYamlTypeConverter +{ + public bool Accepts(Type type) => type == typeof(GameManagerDTO); + + public object ReadYaml(IParser parser, Type type) + { + if (parser.Current is not MappingStart) + throw new InvalidOperationException("Expected MappingStart"); + + parser.MoveNext(); + var gameManager = new GameManagerDTO(); + while (parser.Current != null && parser.Current is not MappingEnd) + { + var propertyName = ((Scalar)parser.Current).Value; + parser.MoveNext(); + switch (propertyName) + { + case nameof(GameManagerDTO.ClassType): + gameManager.ClassType = ((Scalar)parser.Current).Value; + break; + case nameof(GameManagerDTO.GameObjects): + gameManager.GameObjects = (List)new GameObjectDTOListConverter().ReadYaml(parser, typeof(List)); + break; + } + parser.MoveNext(); + } + return gameManager; + } + + public void WriteYaml(IEmitter emitter, object? value, Type type) + { + var gameManager = (GameManagerDTO)(value ?? throw new Exception()); + + GameObjectDTOListConverter gameObjectDTOListConverter = new(); + + emitter.Emit(new MappingStart()); + emitter.Emit(new Scalar(nameof(GameManagerDTO.ClassType))); + emitter.Emit(new Scalar(gameManager.ClassType)); + emitter.Emit(new Scalar(nameof(GameManagerDTO.GameObjects))); + gameObjectDTOListConverter.WriteYaml(emitter, gameManager.GameObjects, typeof(List)); + emitter.Emit(new MappingEnd()); + } +} diff --git a/Engine.Serialization/GameObjectDTOListConverter.cs b/Engine.Serialization/GameObjectDTOListConverter.cs new file mode 100644 index 0000000..351dfa9 --- /dev/null +++ b/Engine.Serialization/GameObjectDTOListConverter.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 GameObjectDTOListConverter : IYamlTypeConverter +{ + public bool Accepts(Type type) + { + return type == typeof(List); + } + + public object ReadYaml(IParser parser, Type type) + { + var gameObjects = new List(); + if (parser.Current is SequenceStart) + { + parser.MoveNext(); + while (parser.Current != null && !(parser.Current is SequenceEnd)) + { + gameObjects.Add((GameObjectDTO)new GameObjectYamlConverter().ReadYaml(parser, typeof(GameObjectDTO))); + parser.MoveNext(); + } + } + return gameObjects; + } + + public void WriteYaml(IEmitter emitter, object? value, Type type) + { + var gameObjects = (List)(value ?? throw new Exception()); + emitter.Emit(new SequenceStart(null, null, false, SequenceStyle.Block)); + foreach (var gameObject in gameObjects) + new GameObjectYamlConverter().WriteYaml(emitter, gameObject, typeof(BehaviourDTO)); + emitter.Emit(new SequenceEnd()); + } +} diff --git a/Engine.Serialization/InternalExtensions.cs b/Engine.Serialization/InternalExtensions.cs index c8653c1..1a47640 100644 --- a/Engine.Serialization/InternalExtensions.cs +++ b/Engine.Serialization/InternalExtensions.cs @@ -12,6 +12,15 @@ internal static class InternalExtensions public static GameObjectDTO ToDTO(this IGameObject gameObject) => new(gameObject.GetType().FullName ?? throw new System.Exception(), gameObject.Id, gameObject.Name, gameObject.Transform.ToDTO(), gameObject.BehaviourController.ToDTO(), gameObject.StateEnable.ToDTO()); + public static GameManagerDTO ToDTO(this IGameManager gameManager) + { + List dtos = []; + foreach (var gameObject in gameManager) + dtos.Add(gameObject.ToDTO()); + + return new(gameManager.GetType().FullName ?? throw new System.Exception(), dtos); + } + public static StateEnableDTO ToDTO(this IStateEnable stateEnable) => new(stateEnable.GetType().FullName ?? throw new System.Exception(), stateEnable.Enabled); diff --git a/Engine.Serialization/Serialization.cs b/Engine.Serialization/Serialization.cs index 6ae6026..da4f51e 100644 --- a/Engine.Serialization/Serialization.cs +++ b/Engine.Serialization/Serialization.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Engine.Serialization.DTOs; using Syntriax.Engine.Core; using Syntriax.Engine.Core.Abstract; @@ -14,11 +15,44 @@ public static class Serialization public static T DeserializeGameObject(string serializedString) where T : class, IGameObject { GameObjectDTO gameObjectDTO = Deserialize(serializedString, defaultSerializer); + return CreateGameObject(gameObjectDTO); + } + + private static T CreateGameObject(GameObjectDTO gameObjectDTO) where T : class, IGameObject + { Type gameObjectType = (gameObjectDTO.ClassType is not null) ? TypeFactory.Get(gameObjectDTO.ClassType) : typeof(GameObject); - T t = new GameObjectFactory().Instantiate(gameObjectType); + Type stateEnableType = (gameObjectDTO.StateEnable.ClassType is not null) ? TypeFactory.Get(gameObjectDTO.StateEnable.ClassType) : typeof(Transform); + Type transformType = (gameObjectDTO.Transform.ClassType is not null) ? TypeFactory.Get(gameObjectDTO.Transform.ClassType) : typeof(Transform); + Type behaviourControllerType = (gameObjectDTO.BehaviourController.ClassType is not null) ? TypeFactory.Get(gameObjectDTO.BehaviourController.ClassType) : typeof(Transform); + + ITransform transform = TypeFactory.Get(transformType); + IStateEnable stateEnable = TypeFactory.Get(stateEnableType); + IBehaviourController behaviourController = TypeFactory.Get(behaviourControllerType); + T t = new GameObjectFactory().Instantiate(transform, behaviourController, stateEnable, gameObjectType); + + foreach (var behaviourDto in gameObjectDTO.BehaviourController.Behaviours) + { + IBehaviour behaviour = TypeFactory.Get(behaviourDto.ClassType); + behaviourController.AddBehaviour(behaviour); + } + return t; } + public static string SerializeGameManager(IGameManager gameManager) => Serialize(gameManager.ToDTO(), defaultSerializer); + public static T DeserializeGameManager(string serializedString) where T : class, IGameManager + { + GameManagerDTO gameManagerDto = Deserialize(serializedString, defaultSerializer); + + Type gameManagerType = (gameManagerDto.ClassType is not null) ? TypeFactory.Get(gameManagerDto.ClassType) : typeof(GameManager); + T gameManager = TypeFactory.Get(gameManagerType); + + foreach (var gameObjectDto in gameManagerDto.GameObjects) + gameManager.RegisterGameObject(CreateGameObject(gameObjectDto)); + + return gameManager; + } + public static string Serialize(T @object) => Serialize(@object, defaultSerializer); public static string Serialize(T @object, ISerializer serializer) => serializer.Serialize(@object); diff --git a/Engine.Serialization/YamlSerializer.cs b/Engine.Serialization/YamlSerializer.cs index b6fa71b..2969937 100644 --- a/Engine.Serialization/YamlSerializer.cs +++ b/Engine.Serialization/YamlSerializer.cs @@ -7,19 +7,27 @@ public class YamlSerializer : ISerializer { private readonly YamlDotNet.Serialization.ISerializer serializer = new SerializerBuilder() .WithNamingConvention(CamelCaseNamingConvention.Instance) + // .WithTypeConverter(new BehaviourYamlConverter()) + // .WithTypeConverter(new BehaviourControllerYamlConverter()) + // .WithTypeConverter(new BehaviourDTOListConverter()) + // .WithTypeConverter(new GameManagerYamlConverter()) + // .WithTypeConverter(new GameObjectYamlConverter()) + // .WithTypeConverter(new GameObjectDTOListConverter()) + // .WithTypeConverter(new StateEnableYamlConverter()) + // .WithTypeConverter(new TransformYamlConverter()) .WithTypeConverter(new Vector2DYamlConverter()) - .WithTypeConverter(new TransformYamlConverter()) - .WithTypeConverter(new BehaviourYamlConverter()) - .WithTypeConverter(new GameObjectYamlConverter()) - .WithTypeConverter(new StateEnableYamlConverter()) .Build(); private readonly YamlDotNet.Serialization.IDeserializer deserializer = new DeserializerBuilder() .WithNamingConvention(UnderscoredNamingConvention.Instance) + // .WithTypeConverter(new BehaviourYamlConverter()) + // .WithTypeConverter(new BehaviourControllerYamlConverter()) + // .WithTypeConverter(new BehaviourDTOListConverter()) + // .WithTypeConverter(new GameManagerYamlConverter()) + // .WithTypeConverter(new GameObjectYamlConverter()) + // .WithTypeConverter(new GameObjectDTOListConverter()) + // .WithTypeConverter(new StateEnableYamlConverter()) + // .WithTypeConverter(new TransformYamlConverter()) .WithTypeConverter(new Vector2DYamlConverter()) - .WithTypeConverter(new TransformYamlConverter()) - .WithTypeConverter(new BehaviourYamlConverter()) - .WithTypeConverter(new GameObjectYamlConverter()) - .WithTypeConverter(new StateEnableYamlConverter()) .Build(); public string Serialize(T @object) => serializer.Serialize(@object);