diff --git a/GlitchyEngine/src/Scripting/ScriptGlue.bf b/GlitchyEngine/src/Scripting/ScriptGlue.bf index fb71c68..242e554 100644 --- a/GlitchyEngine/src/Scripting/ScriptGlue.bf +++ b/GlitchyEngine/src/Scripting/ScriptGlue.bf @@ -1151,7 +1151,7 @@ static class ScriptGlue char8* rawTypeName = Mono.mono_string_to_utf8(typeName); - SerializedObject newObject = new SerializedObject(context.AllObjects, StringView(rawTypeName)); + SerializedObject newObject = new SerializedObject(context.Serializer, StringView(rawTypeName)); Mono.mono_free(rawTypeName); @@ -1182,9 +1182,9 @@ static class ScriptGlue objectContext = null; - Log.EngineLogger.AssertDebug(context.AllObjects.ContainsKey(context.Id)); + Log.EngineLogger.AssertDebug(context.Serializer.ContainsId(context.Id)); - if (!context.AllObjects.TryGetValue(id, let foundObject)) + if (!context.Serializer.TryGetSerializedObject(id, let foundObject)) return; objectContext = Internal.UnsafeCastToPtr(foundObject); diff --git a/GlitchyEngine/src/Scripting/ScriptInstanceSerializer.bf b/GlitchyEngine/src/Scripting/ScriptInstanceSerializer.bf index b6a8dc3..9988385 100644 --- a/GlitchyEngine/src/Scripting/ScriptInstanceSerializer.bf +++ b/GlitchyEngine/src/Scripting/ScriptInstanceSerializer.bf @@ -40,7 +40,7 @@ public class ScriptInstanceSerializer /// Serializes the given script instance. public void SerializeScriptInstance(ScriptInstance script) { - SerializedObject object = new SerializedObject(_serializedData, script.ScriptClass.FullName, script.EntityId); + SerializedObject object = new SerializedObject(this, script.ScriptClass.FullName, script.EntityId); object.Serialize(script); } @@ -94,4 +94,14 @@ public class ScriptInstanceSerializer { return _serializedData.TryGetValue(id, out object); } + + public bool ContainsId(UUID id) + { + return _serializedData.ContainsKey(id); + } + + internal void AddObject(SerializedObject object) + { + _serializedData.Add(object.Id, object); + } } diff --git a/GlitchyEngine/src/Serialization/SerializedObject.bf b/GlitchyEngine/src/Serialization/SerializedObject.bf index 07f35e3..5cd48a0 100644 --- a/GlitchyEngine/src/Serialization/SerializedObject.bf +++ b/GlitchyEngine/src/Serialization/SerializedObject.bf @@ -9,6 +9,8 @@ using System.Reflection; namespace GlitchyEngine.Serialization; +using internal GlitchyEngine.Scripting; + [BonTarget] class SerializedObject { @@ -33,18 +35,18 @@ class SerializedObject public String TypeName ~ delete:append _; - public Dictionary AllObjects; + public ScriptInstanceSerializer Serializer; private List _ownedString = new List() ~ DeleteContainerAndItems!(_); public append Dictionary Fields = .(); [AllowAppend] - public this(Dictionary allObjects, StringView? typeName, UUID? id = null) + public this(ScriptInstanceSerializer serializer, StringView? typeName, UUID? id = null) { String typeNameCopy = append String(typeName.Value); - AllObjects = allObjects; + Serializer = serializer; if (id == null) { @@ -53,14 +55,14 @@ class SerializedObject { Id = UUID.Create(); } - while (AllObjects.ContainsKey(Id)); + while (Serializer.ContainsId(Id)); } else { Id = id.Value; } - AllObjects.Add(Id, this); + Serializer.AddObject(this); TypeName = typeNameCopy; } @@ -364,7 +366,7 @@ class SerializedObject return name; } - public static Result BonDeserialize(BonReader reader, Dictionary allObjects, BonEnvironment environment = gBonEnv) + public static Result BonDeserialize(BonReader reader, ScriptInstanceSerializer scriptSerializer, int sceneFileVersion, BonEnvironment environment = gBonEnv) { StringView type = Try!(reader.Type()); @@ -372,7 +374,7 @@ class SerializedObject Try!(Deserialize.Value(reader, "ID", let objectId, environment)); - SerializedObject object = new SerializedObject(allObjects, type, objectId); + SerializedObject object = new SerializedObject(scriptSerializer, type, objectId); while (reader.ObjectHasMore()) { diff --git a/GlitchyEngine/src/World/SceneSerializer.bf b/GlitchyEngine/src/World/SceneSerializer.bf index 4e1b8c3..7fa7923 100644 --- a/GlitchyEngine/src/World/SceneSerializer.bf +++ b/GlitchyEngine/src/World/SceneSerializer.bf @@ -18,6 +18,8 @@ using internal GlitchyEngine.World; class SceneSerializer { + private const int FileVersion = 1; + private Scene _scene; // Maps from ParentID to ChildEntity @@ -32,6 +34,8 @@ class SceneSerializer private HashSet _objectsNotWritten; + private int _fileVersion; + public ScriptInstanceSerializer ScriptSerializer => _scriptSerializer; public this(Scene scene) @@ -62,7 +66,9 @@ class SceneSerializer { // TODO: Scene name goes here! Serialize.Value(writer, "Name", "Scene name here pls!!!"); - + + Serialize.Value(writer, "Version", FileVersion); + writer.Identifier("Entities"); using (writer.ArrayBlock()) @@ -280,6 +286,31 @@ class SceneSerializer Runtime.NotImplemented(); } + private Result DeserializeValue(BonReader reader, StringView identifier, out T value, bool tryEndEntry = true, BonEnvironment env = gBonEnv) + { + Try!(Deserialize.Value(reader, identifier, out value, env)); + + TryEndEntry(reader); + + return .Ok; + } + + private static bool Check(BonReader reader, char8 token, bool consume = true) + { + return reader.[Friend]Check(token, consume); + } + + private static bool TryEndEntry(BonReader reader) + { + if (Check(reader, ',', false)) + { + reader.EntryEnd(); + return true; + } + + return false; + } + public Result Deserialize(StringView filePath, bool loadAsPrefab = false) { Debug.Profiler.ProfileResourceFunction!(); @@ -298,60 +329,35 @@ class SceneSerializer Try!(reader.ObjectBlock()); _scene.Name = Path.GetFileName(filePath, .. scope .()); + + Try!(DeserializeValue(reader, "Version", out _fileVersion)); - // TODO: Scene name goes here! - String testName; - Deserialize.Value(reader, "Name", out testName); - delete testName; - - Try!(reader.EntryEnd()); - - if (Try!(reader.Identifier()) != "Entities") - return .Err; - - Try!(reader.ArrayBlock()); - - bool first = true; - while (reader.ArrayHasMore()) + if (_fileVersion == 0 || _fileVersion > FileVersion) { - if (!first) - { - Try!(reader.EntryEnd()); - } - - Try!(DeserializeEntity(reader, loadAsPrefab)); - - first = false; + Log.EngineLogger.Warning("The scene file either has no version or it's newer than the current editor. Deserialization might fail."); } - Try!(reader.ArrayBlockEnd()); - - Try!(reader.EntryEnd()); - - if (Try!(reader.Identifier()) != "ReferencedObjects") - return .Err; - - Try!(reader.ArrayBlock()); - - first = true; - while (reader.ArrayHasMore()) + while (reader.ObjectHasMore()) { - if (!first) + StringView identifier = Try!(reader.Identifier()); + + switch (identifier) { - Try!(reader.EntryEnd()); + case "Entities": + Try!(DeserializeEntities(reader, loadAsPrefab)); + case "ReferencedObjects": + Try!(DeserializeReferencedObjects(reader)); + default: + Log.EngineLogger.Warning($"Encountered unexpected Identifier \"{identifier}\"."); } - Try!(SerializedObject.BonDeserialize(reader, _scriptSerializer.SerializedObjects, gBonEnv)); - - first = false; + TryEndEntry(reader); } - Try!(reader.ArrayBlockEnd()); - Try!(reader.ObjectBlockEnd()); Try!(Deserialize.End(reader)); - + // Find parents for entities that don't have their parent yet for ((Entity Entity, UUID ParentId) entry in _entitiesMissingParent) { @@ -368,6 +374,38 @@ class SceneSerializer return .Ok; } + private Result DeserializeEntities(BonReader reader, bool loadAsPrefab) + { + Try!(reader.ArrayBlock()); + + while (reader.ArrayHasMore()) + { + Try!(DeserializeEntity(reader, loadAsPrefab)); + + TryEndEntry(reader); + } + + Try!(reader.ArrayBlockEnd()); + + return .Ok; + } + + private Result DeserializeReferencedObjects(BonReader reader) + { + Try!(reader.ArrayBlock()); + + while (reader.ArrayHasMore()) + { + Try!(SerializedObject.BonDeserialize(reader, _scriptSerializer, _fileVersion, gBonEnv)); + + TryEndEntry(reader); + } + + Try!(reader.ArrayBlockEnd()); + + return .Ok; + } + /// Deserializes the next entity in the file /// @param reader the reader /// @param replaceId If false, the ID that is stored in the file will be used as ID in the scene. @@ -406,8 +444,9 @@ class SceneSerializer } Try!(reader.ObjectBlock()); - - Deserialize.Value(reader, "Id", let rawUuid); + + // We must start with the Id because we need to construct the entity! + DeserializeValue(reader, "Id", let rawUuid); UUID uuid = RemapId(UUID(rawUuid)); @@ -415,58 +454,65 @@ class SceneSerializer while(reader.ObjectHasMore()) { - Try!(reader.EntryEnd()); + TryEndEntry(reader); - StringView identifier = Try!(reader.Identifier()); + StringView componentIdentifier = Try!(reader.Identifier()); - switch(identifier) + switch(componentIdentifier) { case "NameComponent": Try!(DeserializeComponent(reader, entity, scope (component) => { - String name; - - Deserialize.Value(reader, "Name", out name); - + Try!(Deserialize.Value(reader, "Name", let name)); component.Name = name; - delete name; return .Ok; })); case "SpriteRendererComponent": - Try!(DeserializeComponent(reader, entity, scope (component) => + Try!(DeserializeComponentFields(reader, componentIdentifier, entity, scope (component, fieldIdentifier) => { - Try!(Deserialize.Value(reader, "Color", out component.Color)); - reader.EntryEnd(); - Try!(Deserialize.Value(reader, "Sprite", out component.Sprite)); - reader.EntryEnd(); - Try!(Deserialize.Value(reader, "UvTransform", out component.UvTransform)); + switch(fieldIdentifier) + { + case "Color": + Try!(Deserialize.Value(reader, out component.Color)); + case "Sprite": + Try!(Deserialize.Value(reader, out component.Sprite)); + case "UvTransform": + Try!(Deserialize.Value(reader, out component.UvTransform)); + default: + return false; + } - return .Ok; + return true; })); case "CircleRendererComponent": - Try!(DeserializeComponent(reader, entity, scope (component) => + Try!(DeserializeComponentFields(reader, componentIdentifier, entity, scope (component, fieldIdentifier) => { - Try!(Deserialize.Value(reader, "Color", out component.Color)); - reader.EntryEnd(); - Try!(Deserialize.Value(reader, "InnerRadius", out component.InnerRadius)); - reader.EntryEnd(); - Try!(Deserialize.Value(reader, "Sprite", out component.Sprite)); - reader.EntryEnd(); - Try!(Deserialize.Value(reader, "UvTransform", out component.UvTransform)); + switch(fieldIdentifier) + { + case "Color": + Try!(Deserialize.Value(reader, out component.Color)); + case "InnerRadius": + Try!(Deserialize.Value(reader, out component.InnerRadius)); + case "Sprite": + Try!(Deserialize.Value(reader, out component.Sprite)); + case "UvTransform": + Try!(Deserialize.Value(reader, out component.UvTransform)); + default: + return false; + } - return .Ok; + return true; })); case "TransformComponent": - Try!(DeserializeComponent(reader, entity, scope (component) => + Try!(DeserializeComponentFields(reader, componentIdentifier, entity, scope (component, fieldIdentifier) => { - let nextId = Try!(reader.Identifier()); - if (nextId == "ParentId") + switch(fieldIdentifier) { + case "ParentId": UUID rawParentId; - Deserialize.Value(reader, out rawParentId); - reader.EntryEnd(); + Try!(Deserialize.Value(reader, out rawParentId)); UUID parentId = RemapId(rawParentId); @@ -480,155 +526,170 @@ class SceneSerializer { _entitiesMissingParent.Add((entity, parentId)); } - - Deserialize.Value(reader, "Position", out component.[Friend]_position); - reader.EntryEnd(); + case "Position": + Try!(Deserialize.Value(reader, out component.[Friend]_position)); + case "Rotation": + Try!(Deserialize.Value(reader, out component.[Friend]_rotation)); + case "Scale": + Try!(Deserialize.Value(reader, out component.[Friend]_scale)); + case "EditorEulerRotation": + Try!(Deserialize.Value(reader, out component.[Friend]_editorRotationEuler)); + default: + return false; } - else if (nextId == "Position") - { - Deserialize.Value(reader, out component.[Friend]_position); - reader.EntryEnd(); - } - else - { - return .Err; - } - - Deserialize.Value(reader, "Rotation", out component.[Friend]_rotation); - reader.EntryEnd(); - Deserialize.Value(reader, "Scale", out component.[Friend]_scale); - reader.EntryEnd(); - - Deserialize.Value(reader, "EditorEulerRotation", out component.[Friend]_editorRotationEuler); component.IsDirty = true; - return .Ok; + return true; })); case "CameraComponent": - Try!(DeserializeComponent(reader, entity, scope (component) => - { - SceneCamera camera = component.Camera; + Try!(DeserializeComponentFields(reader, componentIdentifier, entity, scope (component, fieldIdentifier) => + { + ref SceneCamera camera = ref component.Camera; - Deserialize.Value(reader, "Primary", out component.Primary); - reader.EntryEnd(); + switch(fieldIdentifier) + { + case "Primary": + Try!(Deserialize.Value(reader, out component.Primary)); + case "ProjectionType": + Try!(Deserialize.Value(reader, out camera.[Friend]_projectionType)); - // TODO: Render target + case "PerspectiveFovY": + Try!(Deserialize.Value(reader, out camera.[Friend]_perspectiveFovY)); + case "PerspectiveNearPlane": + Try!(Deserialize.Value(reader, out camera.[Friend]_perspectiveNearPlane)); + case "PerspectiveFarPlane": + Try!(Deserialize.Value(reader, out camera.[Friend]_perspectiveFarPlane)); - Deserialize.Value(reader, "ProjectionType", out camera.[Friend]_projectionType); - reader.EntryEnd(); + case "OrthographicHeight": + Try!(Deserialize.Value(reader, out camera.[Friend]_orthographicHeight)); + case "OrthographicNearPlane": + Try!(Deserialize.Value(reader, out camera.[Friend]_orthographicNearPlane)); + case "OrthographicFarPlane": + Try!(Deserialize.Value(reader, out camera.[Friend]_orthographicFarPlane)); + case "AspectRatio": + Try!(Deserialize.Value(reader, out camera.[Friend]_aspectRatio)); + case "FixedAspectRatio": + Try!(Deserialize.Value(reader, out camera.[Friend]_fixedAspectRatio)); + default: + return false; + } - Deserialize.Value(reader, "PerspectiveFovY", out camera.[Friend]_perspectiveFovY); - reader.EntryEnd(); - Deserialize.Value(reader, "PerspectiveNearPlane", out camera.[Friend]_perspectiveNearPlane); - reader.EntryEnd(); - Deserialize.Value(reader, "PerspectiveFarPlane", out camera.[Friend]_perspectiveFarPlane); - reader.EntryEnd(); - Deserialize.Value(reader, "OrthographicHeight", out camera.[Friend]_orthographicHeight); - reader.EntryEnd(); - Deserialize.Value(reader, "OrthographicNearPlane", out camera.[Friend]_orthographicNearPlane); - reader.EntryEnd(); - Deserialize.Value(reader, "OrthographicFarPlane", out camera.[Friend]_orthographicFarPlane); - reader.EntryEnd(); - Deserialize.Value(reader, "AspectRatio", out camera.[Friend]_aspectRatio); - reader.EntryEnd(); - Deserialize.Value(reader, "FixedAspectRatio", out camera.[Friend]_fixedAspectRatio); - - camera.[Friend]CalculateProjection(); - - return .Ok; - })); + return true; + })); case "LightComponent": - Try!(DeserializeComponent(reader, entity, scope (component) => + Try!(DeserializeComponentFields(reader, componentIdentifier, entity, scope (component, fieldIdentifier) => { ref SceneLight light = ref component.SceneLight; - Deserialize.Value(reader, "LightType", out light.[Friend]_type); - reader.EntryEnd(); + switch(fieldIdentifier) + { + case "LightType": + Try!(Deserialize.Value(reader, out light.[Friend]_type)); + case "Illuminance": + Try!(Deserialize.Value(reader, out light.[Friend]_illuminance)); + case "Color": + Try!(Deserialize.Value(reader, out light.[Friend]_color)); + default: + return false; + } - Deserialize.Value(reader, "Illuminance", out light.[Friend]_illuminance); - reader.EntryEnd(); - - Deserialize.Value(reader, "Color", out light.[Friend]_color); - return .Ok; + return true; })); case "Rigidbody2D": - Try!(DeserializeComponent(reader, entity, scope (component) => + Try!(DeserializeComponentFields(reader, componentIdentifier, entity, scope (component, fieldIdentifier) => { - Rigidbody2DComponent.BodyType bodyType = .Static; - Deserialize.Value(reader, "BodyType", out bodyType); - component.BodyType = bodyType; + switch(fieldIdentifier) + { + case "BodyType": + Rigidbody2DComponent.BodyType bodyType = .Static; + Try!(Deserialize.Value(reader, out bodyType)); + component.BodyType = bodyType; + case "FixedRotation": + Try!(Deserialize.Value(reader, let fixedRotation)); + component.FixedRotation = fixedRotation; + case "GravityScale": + Try!(Deserialize.Value(reader, let gravityScale)); + component.GravityScale = gravityScale; + default: + return false; + } - reader.EntryEnd(); - - bool fixedRotation = false; - Deserialize.Value(reader, "FixedRotation", out fixedRotation); - component.FixedRotation = fixedRotation; - - reader.EntryEnd(); - - Deserialize.Value(reader, "GravityScale", let gravityScale); - component.GravityScale = gravityScale; - - return .Ok; + return true; })); case "BoxCollider2D": - Try!(DeserializeComponent(reader, entity, scope (component) => + Try!(DeserializeComponentFields(reader, componentIdentifier, entity, scope (component, fieldIdentifier) => { - Deserialize.Value(reader, "Offset", out component.Offset); - reader.EntryEnd(); - Deserialize.Value(reader, "Size", out component.Size); - reader.EntryEnd(); - - Deserialize.Value(reader, "Density", out component.Density); - reader.EntryEnd(); - Deserialize.Value(reader, "Friction", out component.Friction); - reader.EntryEnd(); - Deserialize.Value(reader, "Restitution", out component.Restitution); - reader.EntryEnd(); - Deserialize.Value(reader, "RestitutionThreshold", out component.RestitutionThreshold); + switch(fieldIdentifier) + { + case "Offset": + Try!(Deserialize.Value(reader, out component.Offset)); + case "Size": + Try!(Deserialize.Value(reader, out component.Size)); - return .Ok; + case "Density": + Try!(Deserialize.Value(reader, out component.Density)); + case "Friction": + Try!(Deserialize.Value(reader, out component.Friction)); + case "Restitution": + Try!(Deserialize.Value(reader, out component.Restitution)); + case "RestitutionThreshold": + Try!(Deserialize.Value(reader, out component.RestitutionThreshold)); + default: + return false; + } + + return true; })); case "CircleCollider2D": - Try!(DeserializeComponent(reader, entity, scope (component) => + Try!(DeserializeComponentFields(reader, componentIdentifier, entity, scope (component, fieldIdentifier) => { - Deserialize.Value(reader, "Offset", out component.Offset); - reader.EntryEnd(); - Deserialize.Value(reader, "Radius", out component.Radius); - reader.EntryEnd(); - - Deserialize.Value(reader, "Density", out component.Density); - reader.EntryEnd(); - Deserialize.Value(reader, "Friction", out component.Friction); - reader.EntryEnd(); - Deserialize.Value(reader, "Restitution", out component.Restitution); - reader.EntryEnd(); - Deserialize.Value(reader, "RestitutionThreshold", out component.RestitutionThreshold); + switch(fieldIdentifier) + { + case "Offset": + Try!(Deserialize.Value(reader, out component.Offset)); + case "Radius": + Try!(Deserialize.Value(reader, out component.Radius)); - return .Ok; + case "Density": + Try!(Deserialize.Value(reader, out component.Density)); + case "Friction": + Try!(Deserialize.Value(reader, out component.Friction)); + case "Restitution": + Try!(Deserialize.Value(reader, out component.Restitution)); + case "RestitutionThreshold": + Try!(Deserialize.Value(reader, out component.RestitutionThreshold)); + default: + return false; + } + + return true; })); case "PolygonCollider2D": - Try!(DeserializeComponent(reader, entity, scope (component) => + Try!(DeserializeComponentFields(reader, componentIdentifier, entity, scope (component, fieldIdentifier) => { - Deserialize.Value(reader, "Offset", out component.Offset); - reader.EntryEnd(); + switch(fieldIdentifier) + { + case "Offset": + Try!(Deserialize.Value(reader, out component.Offset)); + case "Vertices": + Try!(Deserialize.Value(reader, out component.Vertices)); + case "VertexCount": + Try!(Deserialize.Value(reader, out component.VertexCount)); - Deserialize.Value(reader, "Vertices", out component.Vertices); - reader.EntryEnd(); - Deserialize.Value(reader, "VertexCount", out component.VertexCount); - reader.EntryEnd(); + case "Density": + Try!(Deserialize.Value(reader, out component.Density)); + case "Friction": + Try!(Deserialize.Value(reader, out component.Friction)); + case "Restitution": + Try!(Deserialize.Value(reader, out component.Restitution)); + case "RestitutionThreshold": + Try!(Deserialize.Value(reader, out component.RestitutionThreshold)); + default: + return false; + } - - Deserialize.Value(reader, "Density", out component.Density); - reader.EntryEnd(); - Deserialize.Value(reader, "Friction", out component.Friction); - reader.EntryEnd(); - Deserialize.Value(reader, "Restitution", out component.Restitution); - reader.EntryEnd(); - Deserialize.Value(reader, "RestitutionThreshold", out component.RestitutionThreshold); - - return .Ok; + return true; })); case "MeshComponent": Try!(DeserializeComponent(reader, entity, scope (component) => @@ -645,29 +706,21 @@ class SceneSerializer return .Ok; })); case "ScriptComponent": - Try!(DeserializeComponent(reader, entity, scope (component) => + Try!(DeserializeComponentFields(reader, componentIdentifier, entity, scope (component, fieldIdentifier) => { - String scriptClassName = null; - - Try!(Deserialize.Value(reader, "ScriptClass", out scriptClassName)); - - if (scriptClassName != null) + switch(fieldIdentifier) { + case "ScriptClass": + Try!(Deserialize.Value(reader, let scriptClassName)); component.ScriptClassName = scriptClassName; - delete scriptClassName; + case "Fields": + Try!(SerializedObject.BonDeserialize(reader, _scriptSerializer, _fileVersion, gBonEnv)); + default: + return false; } - - if (reader.ObjectHasMore()) - { - Try!(reader.EntryEnd()); - - if (Try!(reader.Identifier()) == "Fields") - SerializedObject.BonDeserialize(reader, _scriptSerializer.SerializedObjects, gBonEnv); - } - - return .Ok; + return true; })); case "Editor": Try!(DeserializeComponent(reader, entity, scope (component) => @@ -677,106 +730,34 @@ class SceneSerializer return .Ok; })); case "TextRenderer": - Try!(DeserializeComponent(reader, entity, scope (component) => + Try!(DeserializeComponentFields(reader, componentIdentifier, entity, scope (component, fieldIdentifier) => { - Try!(Deserialize.Value(reader, "IsRichText", let isRichText)); - component.IsRichText = isRichText; - - Try!(reader.EntryEnd()); - - String text = null; - - Try!(Deserialize.Value(reader, "Text", out text)); - - if (text != null) + switch(fieldIdentifier) { + case "IsRichText": + Try!(Deserialize.Value(reader, let isRichText)); + component.IsRichText = isRichText; + case "Text": + Try!(Deserialize.Value(reader, let text)); component.Text = text; - delete text; + default: + return false; } - return .Ok; + return true; })); default: - Log.EngineLogger.AssertDebug(false, "Unknown component type"); - //return .Err; + Log.EngineLogger.Error($"Unknown component type \"{componentIdentifier}\" in entity {entity.UUID}"); + return .Err; } } Try!(reader.ObjectBlockEnd()); return .Ok; - - /*writer.EntryStart(); - - using (writer.ObjectBlock()) - { - // TODO: Entity GUID goes here! - Serialize.Value(writer, "Id", entity.Handle.Index); - - SerializeComponent(writer, entity, "EditorComponent", scope (component) => {}); - - SerializeComponent(writer, entity, "NameComponent", scope (component) => - { - Serialize.Value(writer, "Name", component.DebugName); - }); - - SerializeComponent(writer, entity, "SpriterRendererComponent", scope (component) => - { - // TODO: Texture - - Serialize.Value(writer, "Color", component.Color); - }); - - SerializeComponent(writer, entity, "TransformComponent", scope (component) => - { - // TODO: Use GUIDs - if (component.Parent != .InvalidEntity) - Serialize.Value(writer, "ParentId", component.Parent.Index); - - Serialize.Value(writer, "Position", component.Position); - Serialize.Value(writer, "Rotation", component.Rotation); - Serialize.Value(writer, "Scale", component.Scale); - - Serialize.Value(writer, "EditorEulerRotation", component.EditorRotationEuler); - }); - - SerializeComponent(writer, entity, "CameraComponent", scope (component) => - { - SceneCamera camera = component.Camera; - - Serialize.Value(writer, "Primary", component.Primary); - - // TODO: Render target - - Serialize.Value(writer, "ProjectionType", camera.ProjectionType); - - Serialize.Value(writer, "PerspectiveFovY", camera.PerspectiveFovY); - Serialize.Value(writer, "PerspectiveNearPlane", camera.PerspectiveNearPlane); - Serialize.Value(writer, "PerspectiveFarPlane", camera.PerspectiveFarPlane); - Serialize.Value(writer, "OrthographicHeight", camera.OrthographicHeight); - Serialize.Value(writer, "OrthographicNearPlane", camera.OrthographicNearPlane); - Serialize.Value(writer, "OrthographicFarPlane", camera.OrthographicFarPlane); - Serialize.Value(writer, "AspectRatio", camera.AspectRatio); - Serialize.Value(writer, "FixedAspectRatio", camera.FixedAspectRatio); - }); - - - SerializeComponent(writer, entity, "LightComponent", scope (component) => - { - SceneLight light = component.SceneLight; - - Serialize.Value(writer, "LightType", light.LightType); - - Serialize.Value(writer, "Illuminance", light.Illuminance); - - Serialize.Value(writer, "Color", light.Color); - }); - } - - writer.EntryEnd();*/ } - + static Result DeserializeComponent(BonReader reader, Entity entity, delegate Result(T* component) deserialize) where T : struct, new { Try!(reader.ObjectBlock()); @@ -795,6 +776,35 @@ class SceneSerializer return .Ok; } + static Result DeserializeComponentFields(BonReader reader, StringView prettyComponentName, Entity entity, delegate Result(T* component, StringView identifier) deserializeField) where T : struct, new + { + Try!(reader.ObjectBlock()); + + T* component; + + if (entity.HasComponent()) + component = entity.GetComponent(); + else + component = entity.AddComponent(); + + while(reader.ObjectHasMore()) + { + StringView fieldIdentifier = Try!(reader.Identifier()); + + if (!Try!(deserializeField(component, fieldIdentifier))) + { + Log.EngineLogger.Error($"Unknown identifier \"{fieldIdentifier}\" in component \"{prettyComponentName}\" of entity {entity.UUID}"); + return .Err; + } + + TryEndEntry(reader); + } + + Try!(reader.ObjectBlockEnd()); + + return .Ok; + } + public bool DeserializeRuntime(StringView filePath) { Runtime.NotImplemented();