From 0155a38ae601c2756d86bb214f04c1bf690bb2c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20L=C3=BCbe=C3=9F?= Date: Wed, 16 Nov 2022 13:09:26 +0100 Subject: [PATCH] UUID --- GlitchyEditor/content/Scenes/childTest.scene | 212 +++++++++++++++++++ GlitchyEditor/content/Scenes/physics2D.scene | 8 +- GlitchyEditor/src/EditorLayer.bf | 15 +- GlitchyEngine/src/Core/UUID.bf | 53 +++++ GlitchyEngine/src/World/Components.bf | 17 ++ GlitchyEngine/src/World/Entity.bf | 3 + GlitchyEngine/src/World/Scene.bf | 27 ++- GlitchyEngine/src/World/SceneSerializer.bf | 53 ++++- 8 files changed, 367 insertions(+), 21 deletions(-) create mode 100644 GlitchyEditor/content/Scenes/childTest.scene create mode 100644 GlitchyEngine/src/Core/UUID.bf diff --git a/GlitchyEditor/content/Scenes/childTest.scene b/GlitchyEditor/content/Scenes/childTest.scene new file mode 100644 index 0000000..494e902 --- /dev/null +++ b/GlitchyEditor/content/Scenes/childTest.scene @@ -0,0 +1,212 @@ +{ + Name = "Scene name here pls!!!", + Entities = [ + { + Id = 6000868443984780499, + NameComponent = { + Name = "Child" + }, + SpriterRendererComponent = { + Color = { + R = 1, + G = 0.388184, + B = 0.090109, + A = 1 + }, + UvTransform = { + X = 0, + Y = 0, + Z = 1, + W = 1 + } + }, + TransformComponent = { + ParentId = 820806682740348099, + Position = { + X = 0, + Y = 0.75, + Z = 0 + }, + Rotation = { + X = 0, + Y = 0, + Z = 0, + W = 1 + }, + Scale = { + X = 0.5, + Y = 0.5, + Z = 1 + }, + EditorEulerRotation = { + X = 0, + Y = 0, + Z = 0 + } + } + }, + { + Id = 820806682740348099, + NameComponent = { + Name = "Quad" + }, + SpriterRendererComponent = { + Color = { + R = 0, + G = 0.551178, + B = 0.328787, + A = 1 + }, + UvTransform = { + X = 0, + Y = 0, + Z = 1, + W = 1 + } + }, + TransformComponent = { + Position = { + X = 0, + Y = 2, + Z = 0 + }, + Rotation = { + X = 0, + Y = 0, + Z = 0, + W = 1 + }, + Scale = { + X = 1, + Y = 1, + Z = 1 + }, + EditorEulerRotation = { + X = 0, + Y = 0, + Z = 0 + } + }, + Rigidbody2D = { + BodyType = .Dynamic, + FixedRotation = false + }, + BoxCollider2D = { + Offset = { + X = 0, + Y = 0 + }, + Size = { + X = 0.5, + Y = 0.5 + }, + Density = 1, + Friction = 0.5, + Restitution = 0, + RestitutionThreshold = 0.5 + } + }, + { + Id = 15398726361722237419, + NameComponent = { + Name = "Floor" + }, + SpriterRendererComponent = { + Color = { + R = 1, + G = 0.941886, + B = 0.401485, + A = 1 + }, + UvTransform = { + X = 0, + Y = 0, + Z = 1, + W = 1 + } + }, + TransformComponent = { + Position = { + X = 0, + Y = -0.5, + Z = 0 + }, + Rotation = { + X = 0, + Y = 0, + Z = 0, + W = 1 + }, + Scale = { + X = 10, + Y = 1, + Z = 1 + }, + EditorEulerRotation = { + X = 0, + Y = 0, + Z = 0 + } + }, + Rigidbody2D = { + BodyType = .Static, + FixedRotation = false + }, + BoxCollider2D = { + Offset = { + X = 0, + Y = 0 + }, + Size = { + X = 0.5, + Y = 0.5 + }, + Density = 1, + Friction = 0.5, + Restitution = 0, + RestitutionThreshold = 0.5 + } + }, + { + Id = 1491484622542812645, + NameComponent = { + Name = "Camera" + }, + TransformComponent = { + Position = { + X = 0, + Y = 1, + Z = -5 + }, + Rotation = { + X = 0, + Y = 0, + Z = 0, + W = 1 + }, + Scale = { + X = 1, + Y = 1, + Z = 1 + }, + EditorEulerRotation = { + X = 0, + Y = 0, + Z = 0 + } + }, + CameraComponent = { + Primary = true, + ProjectionType = .InfinitePerspective, + PerspectiveFovY = 1.308997, + PerspectiveNearPlane = 0.1, + PerspectiveFarPlane = 10000, + OrthographicHeight = 10, + OrthographicNearPlane = 0, + OrthographicFarPlane = 10, + AspectRatio = 2.116827, + FixedAspectRatio = false + } + } + ] +} \ No newline at end of file diff --git a/GlitchyEditor/content/Scenes/physics2D.scene b/GlitchyEditor/content/Scenes/physics2D.scene index 0a75b30..af77592 100644 --- a/GlitchyEditor/content/Scenes/physics2D.scene +++ b/GlitchyEditor/content/Scenes/physics2D.scene @@ -2,7 +2,7 @@ Name = "Scene name here pls!!!", Entities = [ { - Id = 0, + Id = 820806682740348099, NameComponent = { Name = "Quad" }, @@ -63,7 +63,7 @@ } }, { - Id = 1, + Id = 15398726361722237419, NameComponent = { Name = "Floor" }, @@ -124,7 +124,7 @@ } }, { - Id = 2, + Id = 1491484622542812645, NameComponent = { Name = "Camera" }, @@ -160,7 +160,7 @@ OrthographicHeight = 10, OrthographicNearPlane = 0, OrthographicFarPlane = 10, - AspectRatio = 2.329843, + AspectRatio = 2.864979, FixedAspectRatio = false } } diff --git a/GlitchyEditor/src/EditorLayer.bf b/GlitchyEditor/src/EditorLayer.bf index 8384637..3b8baa6 100644 --- a/GlitchyEditor/src/EditorLayer.bf +++ b/GlitchyEditor/src/EditorLayer.bf @@ -389,7 +389,8 @@ namespace GlitchyEditor mat.SetVariable("NormalScaling", Vector2.One); mat.SetVariable("MetallicFactor", 1.0f); mat.SetVariable("RoughnessFactor", 1.0f); - + + // TODO: completely wrong! EcsEntity e = ModelLoader.LoadModel("content/Models/sphere.glb", mat, _scene.[Friend]_ecsWorld, clips, "Sphere 1"); Entity entity = .(e, _scene); @@ -463,14 +464,14 @@ namespace GlitchyEditor _camera.Position = .(-1.5f, 1.5f, -2.5f); _camera.RotationEuler = .(MathHelper.ToRadians(25), MathHelper.ToRadians(35), 0); - /*// Create default camera - { + // Create default camera + /*{ let camEntity = _scene.CreateEntity("Camera"); let transform = camEntity.Transform; transform.Position = - } + }*/ - // Create the default light source + /*// Create the default light source { let lightNtt = _scene.CreateEntity("Light"); let transform = lightNtt.Transform; @@ -480,9 +481,9 @@ namespace GlitchyEditor let light = lightNtt.AddComponent(); light.SceneLight.Illuminance = 10.0f; light.SceneLight.Color = .(1.0f, 0.95f, 0.8f); - }*/ + } - //TestEntitiesWithModels(); + TestEntitiesWithModels();*/ } /// Saves the scene in the file that is was loaded from or saved to last. If there is no such path (i.e. it is a new scene) the save file dialog will open. diff --git a/GlitchyEngine/src/Core/UUID.bf b/GlitchyEngine/src/Core/UUID.bf new file mode 100644 index 0000000..d3a31d3 --- /dev/null +++ b/GlitchyEngine/src/Core/UUID.bf @@ -0,0 +1,53 @@ +using Bon; +using System; +using Bon.Integrated; +using System.Collections; + +namespace GlitchyEngine.Core +{ + [BonTarget] + struct UUID : IHashable + { + [BonInclude] + private uint64 _uuid; + + private static Random s_Random = new .() ~ delete _; + + static this() + { + gBonEnv.typeHandlers.Add(typeof(UUID), + ((.)new => Serialize, (.)new => Deserialize)); + } + + /// Creates a new random UUID. + public this() + { + _uuid = s_Random.NextU64(); + } + + /// Creates a new UUID with the given value. + public this(uint64 uuid) + { + _uuid = uuid; + } + + public int GetHashCode() + { + return (int)_uuid; + } + + static void Serialize(BonWriter writer, ValueView val, BonEnvironment env) + { + UUID uuid = *(UUID*)val.dataPtr; + + Bon.Integrated.Serialize.[Friend]Integer(typeof(uint64), writer, ValueView(typeof(uint64), &uuid._uuid)); + } + + public static Result Deserialize(BonReader reader, ValueView val, BonEnvironment env) + { + Bon.Integrated.Deserialize.[Friend]Integer!(typeof(uint64), reader, val); + + return .Ok; + } + } +} \ No newline at end of file diff --git a/GlitchyEngine/src/World/Components.bf b/GlitchyEngine/src/World/Components.bf index b8451ad..05c7788 100644 --- a/GlitchyEngine/src/World/Components.bf +++ b/GlitchyEngine/src/World/Components.bf @@ -1,6 +1,7 @@ using System; using GlitchyEngine.Math; using GlitchyEngine.Renderer; +using GlitchyEngine.Core; namespace GlitchyEngine.World { @@ -15,6 +16,22 @@ namespace GlitchyEngine.World } } + struct IDComponent + { + public readonly UUID ID; + + /// Create aa new IDComponent with a random UUID. + public this() + { + ID = UUID(); + } + + public this(UUID id) + { + ID = id; + } + } + /// If an entity has the EditorComponent it won't be displayed in the scene hierarchy. struct EditorComponent { diff --git a/GlitchyEngine/src/World/Entity.bf b/GlitchyEngine/src/World/Entity.bf index f4d380d..c7a7910 100644 --- a/GlitchyEngine/src/World/Entity.bf +++ b/GlitchyEngine/src/World/Entity.bf @@ -1,5 +1,6 @@ using System; using System.Collections; +using GlitchyEngine.Core; using internal GlitchyEngine.World; @@ -63,6 +64,8 @@ namespace GlitchyEngine.World } } + public UUID UUID => GetComponent().ID; + public TransformComponent* Transform => GetComponent(); public T* AddComponent(T value = T()) where T: struct, new diff --git a/GlitchyEngine/src/World/Scene.bf b/GlitchyEngine/src/World/Scene.bf index 6fc59ad..30deaee 100644 --- a/GlitchyEngine/src/World/Scene.bf +++ b/GlitchyEngine/src/World/Scene.bf @@ -3,6 +3,7 @@ using GlitchyEngine.Renderer; using System; using System.Collections; using Box2D; +using GlitchyEngine.Core; namespace GlitchyEngine.World { @@ -24,6 +25,9 @@ namespace GlitchyEngine.World private Effect _gammaCorrectEffect ~ _.ReleaseRef(); + // Maps ids to the entities they represent. + private Dictionary _idToEntity = new .() ~ delete _; + public Entity ActiveCamera => { Entity cameraEntity = .(); @@ -205,6 +209,8 @@ namespace GlitchyEngine.World } } + renderTarget = _cameraTarget..AddRef(); + // 3D render Renderer.BeginScene(*primaryCamera, primaryCameraTransform, renderTarget, _compositeTarget); @@ -468,13 +474,20 @@ namespace GlitchyEngine.World } /// Creates a new Entity with the given name. - public Entity CreateEntity(String name = "") + public Entity CreateEntity(String name = "", UUID id = default) { Entity entity = Entity(_ecsWorld.NewEntity(), this); entity.AddComponent(); let nameComponent = entity.AddComponent(); nameComponent.SetName(name.IsEmpty ? "Entity" : name); + + // If no id is given generate a random one. + IDComponent idComponent = (id == default) ? IDComponent() : IDComponent(id); + + entity.AddComponent(idComponent); + + _idToEntity.Add(idComponent.ID, entity.Handle); return entity; } @@ -485,6 +498,8 @@ namespace GlitchyEngine.World */ public void DestroyEntity(Entity entity, bool destroyChildren = false) { + _idToEntity.Remove(entity.UUID); + if (destroyChildren) { for (Entity child in entity.EnumerateChildren) @@ -496,6 +511,16 @@ namespace GlitchyEngine.World _ecsWorld.RemoveEntity(entity.Handle); } + public Result GetEntityByID(UUID id) + { + if (_idToEntity.TryGetValue(id, let ecsEntity)) + { + return .Ok(Entity(ecsEntity, this)); + } + + return .Err; + } + private uint32 ViewportWidth, ViewportHeight; /// Sets the size of the viewport into which the scene will be rendered. diff --git a/GlitchyEngine/src/World/SceneSerializer.bf b/GlitchyEngine/src/World/SceneSerializer.bf index 517c44c..3bf9e51 100644 --- a/GlitchyEngine/src/World/SceneSerializer.bf +++ b/GlitchyEngine/src/World/SceneSerializer.bf @@ -4,6 +4,8 @@ using System; using System.Reflection; using System.IO; using GlitchyEngine.Math; +using GlitchyEngine.Core; +using System.Collections; namespace GlitchyEngine.World { @@ -13,6 +15,11 @@ namespace GlitchyEngine.World { private Scene _scene; + // Maps from ParentID to ChildEntity + private Dictionary _parentIdToChild; + + private List<(Entity Entity, UUID ParentId)> _entitiesMissingParent; + public this(Scene scene) { _scene = scene; @@ -60,14 +67,13 @@ namespace GlitchyEngine.World File.WriteAllText(filePath, buffer); } - static void SerializeEntity(BonWriter writer, Entity entity) + void SerializeEntity(BonWriter writer, Entity entity) { writer.EntryStart(); using (writer.ObjectBlock()) { - // TODO: Entity GUID goes here! - Serialize.Value(writer, "Id", entity.Handle.Index); + Serialize.Value(writer, "Id", entity.UUID); SerializeComponent(writer, entity, "EditorComponent", scope (component) => {}); @@ -88,7 +94,10 @@ namespace GlitchyEngine.World { // TODO: Use GUIDs if (component.Parent != .InvalidEntity) - Serialize.Value(writer, "ParentId", component.Parent.Index); + { + Entity parent = Entity(component.Parent, _scene); + Serialize.Value(writer, "ParentId", parent.UUID); + } Serialize.Value(writer, "Position", component.Position); Serialize.Value(writer, "Rotation", component.Rotation); @@ -177,6 +186,9 @@ namespace GlitchyEngine.World { Debug.Profiler.ProfileResourceFunction!(); + _parentIdToChild = scope Dictionary(); + _entitiesMissingParent = scope List<(Entity Entity, UUID ParentId)>(); + String buffer = scope String(); File.ReadAllText(filePath, buffer); @@ -217,6 +229,19 @@ namespace GlitchyEngine.World Try!(Deserialize.End(reader)); + // Find parents for entities that don't have their parent yet + for ((Entity Entity, UUID ParentId) entry in _entitiesMissingParent) + { + let parentResult = _scene.GetEntityByID(entry.ParentId); + + Log.EngineLogger.Assert(parentResult case .Ok, "Parent entity does not exist."); + + if (parentResult case .Ok(let parent)) + { + entry.Entity.Parent = parent; + } + } + return .Ok; } @@ -224,10 +249,9 @@ namespace GlitchyEngine.World { Try!(reader.ObjectBlock()); - Entity entity = _scene.CreateEntity(); + Deserialize.Value(reader, "Id", let uuid); - // TODO: GUID? - Deserialize.Value(reader, "Id", let id); + Entity entity = _scene.CreateEntity("", UUID(uuid)); while(reader.ObjectHasMore()) { @@ -282,10 +306,21 @@ namespace GlitchyEngine.World let nextId = Try!(reader.Identifier()); if (nextId == "ParentId") { - // TODO: Use GUIDs - uint32 pId; + UUID pId; Deserialize.Value(reader, out pId); reader.EntryEnd(); + + var parentEntity = _scene.GetEntityByID(pId); + + if (parentEntity case .Ok(let parent)) + { + component.Parent = parent.Handle; + } + else + { + _entitiesMissingParent.Add((entity, pId)); + } + Deserialize.Value(reader, "Position", out component.[Friend]_position); reader.EntryEnd(); }