From 2fc1b68f410ca86d84191dbf15926c091779ecac Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Tue, 26 Apr 2022 18:43:39 -0700 Subject: [PATCH] initial serialization structure --- src/ComponentDepot.cs | 24 +++++++++++++++++++++ src/ComponentDepotState.cs | 10 +++++++++ src/ComponentStorage.cs | 37 +++++++++++++++++++++++++++++++- src/ComponentStorageState.cs | 31 +++++++++++++++++++++++++++ src/EntityComponentReader.cs | 41 ++++++++++++++---------------------- src/Renderer.cs | 5 +---- src/System.cs | 34 ++++++++++++------------------ src/World.cs | 35 ++++++++++++++---------------- 8 files changed, 147 insertions(+), 70 deletions(-) create mode 100644 src/ComponentDepotState.cs create mode 100644 src/ComponentStorageState.cs diff --git a/src/ComponentDepot.cs b/src/ComponentDepot.cs index 482214e..bd43661 100644 --- a/src/ComponentDepot.cs +++ b/src/ComponentDepot.cs @@ -231,6 +231,30 @@ namespace MoonTools.ECS filterSignatureToEntityIDs[filterSignature].Add(entityID); } + public ComponentDepotState CreateState() + { + return new ComponentDepotState(); + } + + public void Serialize(ComponentDepotState state) + { + state.StorageStates.Clear(); + foreach (var (type, storage) in storages) + { + var storageState = storage.CreateState(); + storage.Serialize(storageState); + state.StorageStates.Add(type, storageState); + } + } + + public void Deserialize(ComponentDepotState state) + { + foreach (var (type, storageState) in state.StorageStates) + { + storages[type].Deserialize(storageState); + } + } + #if DEBUG public IEnumerable Debug_GetAllComponents(int entityID) { diff --git a/src/ComponentDepotState.cs b/src/ComponentDepotState.cs new file mode 100644 index 0000000..78481d1 --- /dev/null +++ b/src/ComponentDepotState.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; + +namespace MoonTools.ECS +{ + public class ComponentDepotState + { + public Dictionary StorageStates = new Dictionary(); + } +} diff --git a/src/ComponentStorage.cs b/src/ComponentStorage.cs index 15a5db2..51d5750 100644 --- a/src/ComponentStorage.cs +++ b/src/ComponentStorage.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Runtime.InteropServices; namespace MoonTools.ECS { @@ -8,9 +9,11 @@ namespace MoonTools.ECS public abstract bool Has(int entityID); public abstract void Remove(int entityID); public abstract object Debug_Get(int entityID); + public abstract ComponentStorageState CreateState(); + public abstract void Serialize(ComponentStorageState state); + public abstract void Deserialize(ComponentStorageState state); } - // FIXME: we can probably get rid of this weird entity storage system by using filters internal class ComponentStorage : ComponentStorage where TComponent : struct { private int nextID; @@ -106,5 +109,37 @@ namespace MoonTools.ECS { return new Entity(entityIDs[0]); } + + public override ComponentStorageState CreateState() + { + return ComponentStorageState.Create(nextID); + } + + public override void Serialize(ComponentStorageState serializedComponentStorage) + { + ReadOnlySpan entityIDBytes = MemoryMarshal.Cast(new ReadOnlySpan(entityIDs, 0, nextID)); + entityIDBytes.CopyTo(serializedComponentStorage.EntityIDs); + + ReadOnlySpan componentBytes = MemoryMarshal.Cast(AllComponents()); + componentBytes.CopyTo(serializedComponentStorage.Components); + + serializedComponentStorage.EntityIdToStorageIndex.Clear(); + foreach (var kvp in entityIDToStorageIndex) + { + serializedComponentStorage.EntityIdToStorageIndex[kvp.Key] = kvp.Value; + } + } + + public override void Deserialize(ComponentStorageState serializedComponentStorage) + { + serializedComponentStorage.EntityIDs.CopyTo(MemoryMarshal.Cast(entityIDs)); + serializedComponentStorage.Components.CopyTo(MemoryMarshal.Cast(components)); + + entityIDToStorageIndex.Clear(); + foreach (var kvp in serializedComponentStorage.EntityIdToStorageIndex) + { + entityIDToStorageIndex[kvp.Key] = kvp.Value; + } + } } } diff --git a/src/ComponentStorageState.cs b/src/ComponentStorageState.cs new file mode 100644 index 0000000..dd98063 --- /dev/null +++ b/src/ComponentStorageState.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace MoonTools.ECS +{ + // for saving and loading component storage + public class ComponentStorageState + { + public int Count; + public Dictionary EntityIdToStorageIndex; + public byte[] EntityIDs; + public byte[] Components; + + public static ComponentStorageState Create(int count) + { + return new ComponentStorageState( + count, + count * Marshal.SizeOf(), + count * Marshal.SizeOf() + ); + } + + private ComponentStorageState(int count, int entityIDSize, int componentSize) + { + Count = count; + EntityIdToStorageIndex = new Dictionary(count); + EntityIDs = new byte[entityIDSize]; + Components = new byte[componentSize]; + } + } +} diff --git a/src/EntityComponentReader.cs b/src/EntityComponentReader.cs index 5449d95..b39de4f 100644 --- a/src/EntityComponentReader.cs +++ b/src/EntityComponentReader.cs @@ -5,52 +5,43 @@ namespace MoonTools.ECS { public abstract class EntityComponentReader { - internal EntityStorage EntityStorage; - internal ComponentDepot ComponentDepot; - internal RelationDepot RelationDepot; + protected readonly World World; + internal EntityStorage EntityStorage => World.EntityStorage; + internal ComponentDepot ComponentDepot => World.ComponentDepot; + internal RelationDepot RelationDepot => World.RelationDepot; protected FilterBuilder FilterBuilder => new FilterBuilder(ComponentDepot); - internal void RegisterEntityStorage(EntityStorage entityStorage) + public EntityComponentReader(World world) { - EntityStorage = entityStorage; + World = world; } - internal void RegisterComponentDepot(ComponentDepot componentDepot) - { - ComponentDepot = componentDepot; - } - - internal void RegisterRelationDepot(RelationDepot relationDepot) - { - RelationDepot = relationDepot; - } - - protected ReadOnlySpan ReadComponents() where TComponent : struct + protected ReadOnlySpan ReadComponents() where TComponent : unmanaged { return ComponentDepot.ReadComponents(); } - protected bool Has(in Entity entity) where TComponent : struct + protected bool Has(in Entity entity) where TComponent : unmanaged { return ComponentDepot.Has(entity.ID); } - protected bool Some() where TComponent : struct + protected bool Some() where TComponent : unmanaged { return ComponentDepot.Some(); } - protected ref readonly TComponent Get(in Entity entity) where TComponent : struct + protected ref readonly TComponent Get(in Entity entity) where TComponent : unmanaged { return ref ComponentDepot.Get(entity.ID); } - protected ref readonly TComponent GetSingleton() where TComponent : struct + protected ref readonly TComponent GetSingleton() where TComponent : unmanaged { return ref ComponentDepot.Get(); } - protected Entity GetSingletonEntity() where TComponent : struct + protected Entity GetSingletonEntity() where TComponent : unmanaged { return ComponentDepot.GetSingletonEntity(); } @@ -60,22 +51,22 @@ namespace MoonTools.ECS return EntityStorage.Exists(entity); } - protected IEnumerable<(Entity, Entity, TRelationKind)> Relations() where TRelationKind : struct + protected IEnumerable<(Entity, Entity, TRelationKind)> Relations() where TRelationKind : unmanaged { return RelationDepot.Relations(); } - protected bool Related(in Entity a, in Entity b) where TRelationKind : struct + protected bool Related(in Entity a, in Entity b) where TRelationKind : unmanaged { return RelationDepot.Related(a.ID, b.ID); } - protected IEnumerable<(Entity, TRelationKind)> RelatedToA(in Entity entity) where TRelationKind : struct + protected IEnumerable<(Entity, TRelationKind)> RelatedToA(in Entity entity) where TRelationKind : unmanaged { return RelationDepot.RelatedToA(entity.ID); } - protected IEnumerable<(Entity, TRelationKind)> RelatedToB(in Entity entity) where TRelationKind : struct + protected IEnumerable<(Entity, TRelationKind)> RelatedToB(in Entity entity) where TRelationKind : unmanaged { return RelationDepot.RelatedToB(entity.ID); } diff --git a/src/Renderer.cs b/src/Renderer.cs index 07531f3..f6118c2 100644 --- a/src/Renderer.cs +++ b/src/Renderer.cs @@ -2,9 +2,6 @@ { public abstract class Renderer : EntityComponentReader { - public Renderer(World world) - { - world.AddRenderer(this); - } + public Renderer(World world) : base(world) { } } } diff --git a/src/System.cs b/src/System.cs index 66eee93..1983d17 100644 --- a/src/System.cs +++ b/src/System.cs @@ -5,17 +5,9 @@ namespace MoonTools.ECS { public abstract class System : EntityComponentReader { - internal MessageDepot MessageDepot; + internal MessageDepot MessageDepot => World.MessageDepot; - internal void RegisterMessageDepot(MessageDepot messageDepot) - { - MessageDepot = messageDepot; - } - - public System(World world) - { - world.AddSystem(this); - } + public System(World world) : base(world) { } public abstract void Update(TimeSpan delta); @@ -24,7 +16,7 @@ namespace MoonTools.ECS return EntityStorage.Create(); } - protected void Set(in Entity entity, in TComponent component) where TComponent : struct + protected void Set(in Entity entity, in TComponent component) where TComponent : unmanaged { #if DEBUG // check for use after destroy @@ -36,52 +28,52 @@ namespace MoonTools.ECS ComponentDepot.Set(entity.ID, component); } - protected void Remove(in Entity entity) where TComponent : struct + protected void Remove(in Entity entity) where TComponent : unmanaged { ComponentDepot.Remove(entity.ID); } - protected ReadOnlySpan ReadMessages() where TMessage : struct + protected ReadOnlySpan ReadMessages() where TMessage : unmanaged { return MessageDepot.All(); } - protected TMessage ReadMessage() where TMessage : struct + protected TMessage ReadMessage() where TMessage : unmanaged { return MessageDepot.First(); } - protected bool SomeMessage() where TMessage : struct + protected bool SomeMessage() where TMessage : unmanaged { return MessageDepot.Some(); } - protected IEnumerable ReadMessagesWithEntity(in Entity entity) where TMessage : struct, IHasEntity + protected IEnumerable ReadMessagesWithEntity(in Entity entity) where TMessage : unmanaged, IHasEntity { return MessageDepot.WithEntity(entity.ID); } - protected ref readonly TMessage ReadMessageWithEntity(in Entity entity) where TMessage : struct, IHasEntity + protected ref readonly TMessage ReadMessageWithEntity(in Entity entity) where TMessage : unmanaged, IHasEntity { return ref MessageDepot.FirstWithEntity(entity.ID); } - protected bool SomeMessageWithEntity(in Entity entity) where TMessage : struct, IHasEntity + protected bool SomeMessageWithEntity(in Entity entity) where TMessage : unmanaged, IHasEntity { return MessageDepot.SomeWithEntity(entity.ID); } - protected void Send(in TMessage message) where TMessage : struct + protected void Send(in TMessage message) where TMessage : unmanaged { MessageDepot.Add(message); } - protected void Relate(in Entity entityA, in Entity entityB, TRelationKind relationData) where TRelationKind : struct + protected void Relate(in Entity entityA, in Entity entityB, TRelationKind relationData) where TRelationKind : unmanaged { RelationDepot.Add(new Relation(entityA, entityB), relationData); } - protected void Unrelate(in Entity entityA, in Entity entityB) where TRelationKind : struct + protected void Unrelate(in Entity entityA, in Entity entityB) where TRelationKind : unmanaged { RelationDepot.Remove(new Relation(entityA, entityB)); } diff --git a/src/World.cs b/src/World.cs index 8e9e97d..1582846 100644 --- a/src/World.cs +++ b/src/World.cs @@ -2,25 +2,10 @@ { public class World { - private readonly EntityStorage EntityStorage = new EntityStorage(); - private readonly ComponentDepot ComponentDepot = new ComponentDepot(); - private readonly MessageDepot MessageDepot = new MessageDepot(); - private readonly RelationDepot RelationDepot = new RelationDepot(); - - internal void AddSystem(System system) - { - system.RegisterEntityStorage(EntityStorage); - system.RegisterComponentDepot(ComponentDepot); - system.RegisterMessageDepot(MessageDepot); - system.RegisterRelationDepot(RelationDepot); - } - - internal void AddRenderer(Renderer renderer) - { - renderer.RegisterEntityStorage(EntityStorage); - renderer.RegisterComponentDepot(ComponentDepot); - renderer.RegisterRelationDepot(RelationDepot); - } + internal readonly EntityStorage EntityStorage = new EntityStorage(); + internal readonly ComponentDepot ComponentDepot = new ComponentDepot(); + internal readonly MessageDepot MessageDepot = new MessageDepot(); + internal readonly RelationDepot RelationDepot = new RelationDepot(); public Entity CreateEntity() { @@ -41,5 +26,17 @@ { MessageDepot.Clear(); } + + public ComponentDepotState Serialize() + { + var state = ComponentDepot.CreateState(); + ComponentDepot.Serialize(state); + return state; + } + + public void Deserialize(ComponentDepotState state) + { + ComponentDepot.Deserialize(state); + } } }