complete world state storage
parent
190d1413ca
commit
8f620c7a20
|
@ -221,7 +221,7 @@ namespace MoonTools.ECS
|
|||
TypesWithDisabledSerialization.Add(typeof(TComponent));
|
||||
}
|
||||
|
||||
public void Serialize(ComponentDepotState state)
|
||||
public void Save(ComponentDepotState state)
|
||||
{
|
||||
foreach (var (type, storage) in storages)
|
||||
{
|
||||
|
@ -232,7 +232,7 @@ namespace MoonTools.ECS
|
|||
state.StorageStates.Add(type, storage.CreateState());
|
||||
}
|
||||
|
||||
storage.Serialize(state.StorageStates[type]);
|
||||
storage.Save(state.StorageStates[type]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -250,11 +250,11 @@ namespace MoonTools.ECS
|
|||
}
|
||||
}
|
||||
|
||||
public void Deserialize(ComponentDepotState state)
|
||||
public void Load(ComponentDepotState state)
|
||||
{
|
||||
foreach (var (type, storageState) in state.StorageStates)
|
||||
{
|
||||
storages[type].Deserialize(storageState);
|
||||
storages[type].Load(storageState);
|
||||
}
|
||||
|
||||
foreach (var (signature, setState) in state.FilterStates)
|
||||
|
|
|
@ -10,8 +10,8 @@ namespace MoonTools.ECS
|
|||
public abstract bool 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);
|
||||
public abstract void Save(ComponentStorageState state);
|
||||
public abstract void Load(ComponentStorageState state);
|
||||
}
|
||||
|
||||
internal class ComponentStorage<TComponent> : ComponentStorage where TComponent : unmanaged
|
||||
|
@ -127,44 +127,38 @@ namespace MoonTools.ECS
|
|||
return ComponentStorageState.Create<TComponent>(nextID);
|
||||
}
|
||||
|
||||
public override void Serialize(ComponentStorageState serializedComponentStorage)
|
||||
public override void Save(ComponentStorageState state)
|
||||
{
|
||||
ReadOnlySpan<byte> entityIDBytes = MemoryMarshal.Cast<int, byte>(new ReadOnlySpan<int>(entityIDs, 0, nextID));
|
||||
|
||||
if (entityIDBytes.Length > serializedComponentStorage.EntityIDs.Length)
|
||||
if (entityIDBytes.Length > state.EntityIDs.Length)
|
||||
{
|
||||
Array.Resize(ref serializedComponentStorage.EntityIDs, entityIDBytes.Length);
|
||||
Array.Resize(ref state.EntityIDs, entityIDBytes.Length);
|
||||
}
|
||||
entityIDBytes.CopyTo(serializedComponentStorage.EntityIDs);
|
||||
entityIDBytes.CopyTo(state.EntityIDs);
|
||||
|
||||
ReadOnlySpan<byte> componentBytes = MemoryMarshal.Cast<TComponent, byte>(AllComponents());
|
||||
if (componentBytes.Length > serializedComponentStorage.Components.Length)
|
||||
if (componentBytes.Length > state.Components.Length)
|
||||
{
|
||||
Array.Resize(ref serializedComponentStorage.Components, componentBytes.Length);
|
||||
Array.Resize(ref state.Components, componentBytes.Length);
|
||||
}
|
||||
componentBytes.CopyTo(serializedComponentStorage.Components);
|
||||
componentBytes.CopyTo(state.Components);
|
||||
|
||||
serializedComponentStorage.EntityIdToStorageIndex.Clear();
|
||||
foreach (var kvp in entityIDToStorageIndex)
|
||||
{
|
||||
serializedComponentStorage.EntityIdToStorageIndex[kvp.Key] = kvp.Value;
|
||||
}
|
||||
|
||||
serializedComponentStorage.Count = nextID;
|
||||
state.Count = nextID;
|
||||
}
|
||||
|
||||
public override void Deserialize(ComponentStorageState serializedComponentStorage)
|
||||
public override void Load(ComponentStorageState state)
|
||||
{
|
||||
serializedComponentStorage.EntityIDs.CopyTo(MemoryMarshal.Cast<int, byte>(entityIDs));
|
||||
serializedComponentStorage.Components.CopyTo(MemoryMarshal.Cast<TComponent, byte>(components));
|
||||
state.EntityIDs.CopyTo(MemoryMarshal.Cast<int, byte>(entityIDs));
|
||||
state.Components.CopyTo(MemoryMarshal.Cast<TComponent, byte>(components));
|
||||
|
||||
entityIDToStorageIndex.Clear();
|
||||
foreach (var kvp in serializedComponentStorage.EntityIdToStorageIndex)
|
||||
for (var i = 0; i < state.Count; i += 1)
|
||||
{
|
||||
entityIDToStorageIndex[kvp.Key] = kvp.Value;
|
||||
entityIDToStorageIndex[entityIDs[i]] = i;
|
||||
}
|
||||
|
||||
nextID = serializedComponentStorage.Count;
|
||||
nextID = state.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace MoonTools.ECS
|
|||
Release(entity.ID);
|
||||
}
|
||||
|
||||
public void Serialize(EntityStorageState state)
|
||||
public void Save(EntityStorageState state)
|
||||
{
|
||||
state.NextID = nextID;
|
||||
state.availableIDs.Clear();
|
||||
|
@ -33,7 +33,7 @@ namespace MoonTools.ECS
|
|||
}
|
||||
}
|
||||
|
||||
public void Deserialize(EntityStorageState state)
|
||||
public void Load(EntityStorageState state)
|
||||
{
|
||||
nextID = state.NextID;
|
||||
availableIDs.Clear();
|
||||
|
|
|
@ -82,12 +82,6 @@ namespace MoonTools.ECS
|
|||
|
||||
public void Save(IndexableSetState<T> state)
|
||||
{
|
||||
state.Indices.Clear();
|
||||
foreach (var (key, value) in indices)
|
||||
{
|
||||
state.Indices[key] = value;
|
||||
}
|
||||
|
||||
ReadOnlySpan<byte> arrayBytes = MemoryMarshal.Cast<T, byte>(array);
|
||||
|
||||
if (arrayBytes.Length > state.Array.Length)
|
||||
|
@ -102,14 +96,14 @@ namespace MoonTools.ECS
|
|||
|
||||
public void Load(IndexableSetState<T> state)
|
||||
{
|
||||
indices.Clear();
|
||||
foreach (var kvp in state.Indices)
|
||||
{
|
||||
indices[kvp.Key] = kvp.Value;
|
||||
}
|
||||
|
||||
state.Array.CopyTo(MemoryMarshal.Cast<T, byte>(array));
|
||||
|
||||
indices.Clear();
|
||||
for (var i = 0; i < state.Count; i += 1)
|
||||
{
|
||||
indices[array[i]] = i;
|
||||
}
|
||||
|
||||
Count = state.Count;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace MoonTools.ECS
|
|||
{
|
||||
private Dictionary<Type, RelationStorage> storages = new Dictionary<Type, RelationStorage>();
|
||||
|
||||
private void Register<TRelationKind>() where TRelationKind : struct
|
||||
private void Register<TRelationKind>() where TRelationKind : unmanaged
|
||||
{
|
||||
if (!storages.ContainsKey(typeof(TRelationKind)))
|
||||
{
|
||||
|
@ -15,18 +15,18 @@ namespace MoonTools.ECS
|
|||
}
|
||||
}
|
||||
|
||||
private RelationStorage<TRelationKind> Lookup<TRelationKind>() where TRelationKind : struct
|
||||
private RelationStorage<TRelationKind> Lookup<TRelationKind>() where TRelationKind : unmanaged
|
||||
{
|
||||
Register<TRelationKind>();
|
||||
return (RelationStorage<TRelationKind>) storages[typeof(TRelationKind)];
|
||||
}
|
||||
|
||||
public void Add<TRelationKind>(Relation relation, TRelationKind relationData) where TRelationKind : struct
|
||||
public void Set<TRelationKind>(Relation relation, TRelationKind relationData) where TRelationKind : unmanaged
|
||||
{
|
||||
Lookup<TRelationKind>().Add(relation, relationData);
|
||||
Lookup<TRelationKind>().Set(relation, relationData);
|
||||
}
|
||||
|
||||
public void Remove<TRelationKind>(Relation relation) where TRelationKind : struct
|
||||
public void Remove<TRelationKind>(Relation relation) where TRelationKind : unmanaged
|
||||
{
|
||||
Lookup<TRelationKind>().Remove(relation);
|
||||
}
|
||||
|
@ -40,24 +40,45 @@ namespace MoonTools.ECS
|
|||
}
|
||||
}
|
||||
|
||||
public IEnumerable<(Entity, Entity, TRelationKind)> Relations<TRelationKind>() where TRelationKind : struct
|
||||
public IEnumerable<(Entity, Entity, TRelationKind)> Relations<TRelationKind>() where TRelationKind : unmanaged
|
||||
{
|
||||
return Lookup<TRelationKind>().All();
|
||||
}
|
||||
|
||||
public bool Related<TRelationKind>(int idA, int idB) where TRelationKind : struct
|
||||
public bool Related<TRelationKind>(int idA, int idB) where TRelationKind : unmanaged
|
||||
{
|
||||
return Lookup<TRelationKind>().Has(new Relation(idA, idB));
|
||||
}
|
||||
|
||||
public IEnumerable<(Entity, TRelationKind)> RelatedToA<TRelationKind>(int entityID) where TRelationKind : struct
|
||||
public IEnumerable<(Entity, TRelationKind)> RelatedToA<TRelationKind>(int entityID) where TRelationKind : unmanaged
|
||||
{
|
||||
return Lookup<TRelationKind>().RelatedToA(entityID);
|
||||
}
|
||||
|
||||
public IEnumerable<(Entity, TRelationKind)> RelatedToB<TRelationKind>(int entityID) where TRelationKind : struct
|
||||
public IEnumerable<(Entity, TRelationKind)> RelatedToB<TRelationKind>(int entityID) where TRelationKind : unmanaged
|
||||
{
|
||||
return Lookup<TRelationKind>().RelatedToB(entityID);
|
||||
}
|
||||
|
||||
public void Save(RelationDepotState state)
|
||||
{
|
||||
foreach (var (type, storage) in storages)
|
||||
{
|
||||
if (!state.StorageStates.ContainsKey(type))
|
||||
{
|
||||
state.StorageStates.Add(type, storage.CreateState());
|
||||
}
|
||||
|
||||
storage.Save(state.StorageStates[type]);
|
||||
}
|
||||
}
|
||||
|
||||
public void Load(RelationDepotState state)
|
||||
{
|
||||
foreach (var (type, storageState) in state.StorageStates)
|
||||
{
|
||||
storages[type].Load(storageState);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,32 +1,46 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace MoonTools.ECS
|
||||
{
|
||||
internal abstract class RelationStorage
|
||||
{
|
||||
public abstract RelationStorageState CreateState();
|
||||
public abstract void Save(RelationStorageState state);
|
||||
public abstract void Load(RelationStorageState state);
|
||||
public abstract void OnEntityDestroy(int entityID);
|
||||
}
|
||||
|
||||
// Relation is the two entities, A related to B.
|
||||
// TRelation is the data attached to the relation.
|
||||
internal class RelationStorage<TRelation> : RelationStorage where TRelation : struct
|
||||
internal class RelationStorage<TRelation> : RelationStorage where TRelation : unmanaged
|
||||
{
|
||||
private Dictionary<Relation, TRelation> relations = new Dictionary<Relation, TRelation>(16);
|
||||
private int count = 0;
|
||||
private Dictionary<Relation, int> indices = new Dictionary<Relation, int>(16);
|
||||
private Relation[] relations = new Relation[16];
|
||||
private TRelation[] relationDatas = new TRelation[16];
|
||||
private Dictionary<int, HashSet<int>> entitiesRelatedToA = new Dictionary<int, HashSet<int>>(16);
|
||||
private Dictionary<int, HashSet<int>> entitiesRelatedToB = new Dictionary<int, HashSet<int>>(16);
|
||||
private Stack<HashSet<int>> listPool = new Stack<HashSet<int>>();
|
||||
|
||||
public IEnumerable<(Entity, Entity, TRelation)> All()
|
||||
{
|
||||
foreach (var relationData in relations)
|
||||
for (var i = 0; i < count; i += 1)
|
||||
{
|
||||
yield return (relationData.Key.A, relationData.Key.B, relationData.Value);
|
||||
var relation = relations[i];
|
||||
yield return (relation.A, relation.B, relationDatas[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(Relation relation, TRelation relationData)
|
||||
public void Set(Relation relation, TRelation relationData)
|
||||
{
|
||||
if (relations.ContainsKey(relation)) { return; }
|
||||
if (indices.ContainsKey(relation))
|
||||
{
|
||||
var index = indices[relation];
|
||||
relationDatas[index] = relationData;
|
||||
return;
|
||||
}
|
||||
|
||||
var idA = relation.A.ID;
|
||||
var idB = relation.B.ID;
|
||||
|
@ -43,12 +57,20 @@ namespace MoonTools.ECS
|
|||
}
|
||||
entitiesRelatedToB[idB].Add(idA);
|
||||
|
||||
relations.Add(relation, relationData);
|
||||
if (count >= relationDatas.Length)
|
||||
{
|
||||
Array.Resize(ref relationDatas, relationDatas.Length * 2);
|
||||
}
|
||||
|
||||
relations[count] = relation;
|
||||
relationDatas[count] = relationData;
|
||||
indices.Add(relation, count);
|
||||
count += 1;
|
||||
}
|
||||
|
||||
public bool Has(Relation relation)
|
||||
{
|
||||
return relations.ContainsKey(relation);
|
||||
return indices.ContainsKey(relation);
|
||||
}
|
||||
|
||||
// FIXME: is there a more descriptive name for these?
|
||||
|
@ -59,7 +81,7 @@ namespace MoonTools.ECS
|
|||
foreach (var id in entitiesRelatedToA[entityID])
|
||||
{
|
||||
var relation = new Relation(entityID, id);
|
||||
yield return (relation.B, relations[relation]);
|
||||
yield return (relation.B, relationDatas[indices[relation]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -71,7 +93,7 @@ namespace MoonTools.ECS
|
|||
foreach (var id in entitiesRelatedToB[entityID])
|
||||
{
|
||||
var relation = new Relation(id, entityID);
|
||||
yield return (relation.A, relations[relation]);
|
||||
yield return (relation.A, relationDatas[indices[relation]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -88,7 +110,26 @@ namespace MoonTools.ECS
|
|||
entitiesRelatedToB[relation.B.ID].Remove(relation.A.ID);
|
||||
}
|
||||
|
||||
return relations.Remove(relation);
|
||||
if (indices.ContainsKey(relation))
|
||||
{
|
||||
var index = indices[relation];
|
||||
var lastElementIndex = count - 1;
|
||||
|
||||
// move an element into the hole
|
||||
if (index != lastElementIndex)
|
||||
{
|
||||
var lastRelation = relations[lastElementIndex];
|
||||
indices[lastRelation] = index;
|
||||
relationDatas[index] = relationDatas[lastElementIndex];
|
||||
relations[index] = lastRelation;
|
||||
}
|
||||
|
||||
count -= 1;
|
||||
indices.Remove(relation);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void OnEntityDestroy(int entityID)
|
||||
|
@ -131,5 +172,61 @@ namespace MoonTools.ECS
|
|||
hashSet.Clear();
|
||||
listPool.Push(hashSet);
|
||||
}
|
||||
|
||||
public override RelationStorageState CreateState()
|
||||
{
|
||||
return RelationStorageState.Create<TRelation>(count);
|
||||
}
|
||||
|
||||
public override void Save(RelationStorageState state)
|
||||
{
|
||||
ReadOnlySpan<byte> relationBytes = MemoryMarshal.Cast<Relation, byte>(relations);
|
||||
|
||||
// FIXME: incorrect comparison
|
||||
if (relationBytes.Length > state.Relations.Length)
|
||||
{
|
||||
Array.Resize(ref state.Relations, relationBytes.Length);
|
||||
}
|
||||
relationBytes.CopyTo(state.Relations);
|
||||
|
||||
ReadOnlySpan<byte> relationDataBytes = MemoryMarshal.Cast<TRelation, byte>(relationDatas);
|
||||
|
||||
if (relationDataBytes.Length > state.RelationDatas.Length)
|
||||
{
|
||||
Array.Resize(ref state.RelationDatas, relationDataBytes.Length);
|
||||
}
|
||||
relationDataBytes.CopyTo(state.RelationDatas);
|
||||
|
||||
state.Count = count;
|
||||
}
|
||||
|
||||
public override void Load(RelationStorageState state)
|
||||
{
|
||||
state.Relations.CopyTo(MemoryMarshal.Cast<Relation, byte>(relations));
|
||||
state.RelationDatas.CopyTo(MemoryMarshal.Cast<TRelation, byte>(relationDatas));
|
||||
|
||||
indices.Clear();
|
||||
entitiesRelatedToA.Clear();
|
||||
entitiesRelatedToB.Clear();
|
||||
for (var i = 0; i < state.Count; i += 1)
|
||||
{
|
||||
var relation = relations[i];
|
||||
indices[relation] = i;
|
||||
|
||||
if (!entitiesRelatedToA.ContainsKey(relation.A.ID))
|
||||
{
|
||||
entitiesRelatedToA[relation.A.ID] = AcquireHashSetFromPool();
|
||||
}
|
||||
entitiesRelatedToA[relation.A.ID].Add(relation.B.ID);
|
||||
|
||||
if (!entitiesRelatedToB.ContainsKey(relation.B.ID))
|
||||
{
|
||||
entitiesRelatedToB[relation.B.ID] = AcquireHashSetFromPool();
|
||||
}
|
||||
entitiesRelatedToB[relation.B.ID].Add(relation.A.ID);
|
||||
}
|
||||
|
||||
count = state.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ namespace MoonTools.ECS
|
|||
internal class ComponentStorageState
|
||||
{
|
||||
public int Count;
|
||||
public Dictionary<int, int> EntityIdToStorageIndex;
|
||||
public byte[] EntityIDs;
|
||||
public byte[] Components;
|
||||
|
||||
|
@ -21,7 +20,6 @@ namespace MoonTools.ECS
|
|||
private ComponentStorageState(int count, int entityIDSize, int componentSize)
|
||||
{
|
||||
Count = count;
|
||||
EntityIdToStorageIndex = new Dictionary<int, int>(count);
|
||||
EntityIDs = new byte[entityIDSize];
|
||||
Components = new byte[componentSize];
|
||||
}
|
||||
|
|
|
@ -5,13 +5,11 @@ namespace MoonTools.ECS
|
|||
internal class IndexableSetState<T> where T : unmanaged
|
||||
{
|
||||
public int Count;
|
||||
public Dictionary<T, int> Indices;
|
||||
public byte[] Array;
|
||||
|
||||
public unsafe IndexableSetState(int count)
|
||||
{
|
||||
Count = count;
|
||||
Indices = new Dictionary<T, int>(count);
|
||||
Array = new byte[sizeof(T) * count];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MoonTools.ECS
|
||||
{
|
||||
internal class RelationDepotState
|
||||
{
|
||||
public Dictionary<Type, RelationStorageState> StorageStates = new Dictionary<Type, RelationStorageState>();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace MoonTools.ECS
|
||||
{
|
||||
internal class RelationStorageState
|
||||
{
|
||||
public int Count;
|
||||
public byte[] Relations;
|
||||
public byte[] RelationDatas;
|
||||
|
||||
public unsafe static RelationStorageState Create<TRelation>(int count) where TRelation : unmanaged
|
||||
{
|
||||
return new RelationStorageState(
|
||||
count,
|
||||
count * sizeof(Relation),
|
||||
count * sizeof(TRelation)
|
||||
);
|
||||
}
|
||||
|
||||
private RelationStorageState(int count, int relationSize, int relationDataSize)
|
||||
{
|
||||
Count = count;
|
||||
Relations = new byte[relationSize];
|
||||
RelationDatas = new byte[relationDataSize];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,13 +2,15 @@ namespace MoonTools.ECS
|
|||
{
|
||||
public class WorldState
|
||||
{
|
||||
internal ComponentDepotState ComponentDepotState;
|
||||
internal EntityStorageState EntityStorageState;
|
||||
internal readonly ComponentDepotState ComponentDepotState;
|
||||
internal readonly EntityStorageState EntityStorageState;
|
||||
internal readonly RelationDepotState RelationDepotState;
|
||||
|
||||
public WorldState()
|
||||
{
|
||||
ComponentDepotState = new ComponentDepotState();
|
||||
EntityStorageState = new EntityStorageState();
|
||||
RelationDepotState = new RelationDepotState();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ namespace MoonTools.ECS
|
|||
|
||||
protected void Relate<TRelationKind>(in Entity entityA, in Entity entityB, TRelationKind relationData) where TRelationKind : unmanaged
|
||||
{
|
||||
RelationDepot.Add<TRelationKind>(new Relation(entityA, entityB), relationData);
|
||||
RelationDepot.Set<TRelationKind>(new Relation(entityA, entityB), relationData);
|
||||
}
|
||||
|
||||
protected void Unrelate<TRelationKind>(in Entity entityA, in Entity entityB) where TRelationKind : unmanaged
|
||||
|
|
14
src/World.cs
14
src/World.cs
|
@ -37,16 +37,18 @@
|
|||
return new WorldState();
|
||||
}
|
||||
|
||||
public void Serialize(WorldState state)
|
||||
public void Save(WorldState state)
|
||||
{
|
||||
ComponentDepot.Serialize(state.ComponentDepotState);
|
||||
EntityStorage.Serialize(state.EntityStorageState);
|
||||
ComponentDepot.Save(state.ComponentDepotState);
|
||||
EntityStorage.Save(state.EntityStorageState);
|
||||
RelationDepot.Save(state.RelationDepotState);
|
||||
}
|
||||
|
||||
public void Deserialize(WorldState state)
|
||||
public void Load(WorldState state)
|
||||
{
|
||||
ComponentDepot.Deserialize(state.ComponentDepotState);
|
||||
EntityStorage.Deserialize(state.EntityStorageState);
|
||||
ComponentDepot.Load(state.ComponentDepotState);
|
||||
EntityStorage.Load(state.EntityStorageState);
|
||||
RelationDepot.Load(state.RelationDepotState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue