store entity state + some garbage optimizations

pull/2/head
cosmonaut 2022-05-02 11:07:19 -07:00
parent be95e80265
commit 190d1413ca
9 changed files with 107 additions and 71 deletions

View File

@ -221,36 +221,31 @@ namespace MoonTools.ECS
TypesWithDisabledSerialization.Add(typeof(TComponent)); TypesWithDisabledSerialization.Add(typeof(TComponent));
} }
public ComponentDepotState CreateState()
{
return new ComponentDepotState();
}
public void Serialize(ComponentDepotState state) public void Serialize(ComponentDepotState state)
{ {
// FIXME: this is creating garbage
state.StorageStates.Clear();
foreach (var (type, storage) in storages) foreach (var (type, storage) in storages)
{ {
// FIXME: we could cache this
if (!TypesWithDisabledSerialization.Contains(type)) if (!TypesWithDisabledSerialization.Contains(type))
{ {
var storageState = storage.CreateState(); if (!state.StorageStates.ContainsKey(type))
storage.Serialize(storageState); {
state.StorageStates.Add(type, storageState); state.StorageStates.Add(type, storage.CreateState());
}
storage.Serialize(state.StorageStates[type]);
} }
} }
// FIXME: this is creating garbage
state.FilterStates.Clear();
foreach (var (signature, set) in filterSignatureToEntityIDs) foreach (var (signature, set) in filterSignatureToEntityIDs)
{ {
// FIXME: we could cache this // FIXME: we could cache this
if (!signature.Included.Overlaps(TypesWithDisabledSerialization) && !signature.Excluded.Overlaps(TypesWithDisabledSerialization)) if (!signature.Included.Overlaps(TypesWithDisabledSerialization) && !signature.Excluded.Overlaps(TypesWithDisabledSerialization))
{ {
var setState = new IndexableSetState<int>(set.Count); if (!state.FilterStates.ContainsKey(signature))
set.Save(setState); {
state.FilterStates[signature] = setState; state.FilterStates[signature] = new IndexableSetState<int>(set.Count);
}
set.Save(state.FilterStates[signature]);
} }
} }
} }

View File

@ -1,22 +1,75 @@
namespace MoonTools.ECS using System.Collections.Generic;
namespace MoonTools.ECS
{ {
internal class EntityStorage internal class EntityStorage
{ {
public IDStorage idStorage = new IDStorage(); private int nextID = 0;
private readonly Stack<int> availableIDs = new Stack<int>();
private readonly HashSet<int> availableIDHash = new HashSet<int>();
public Entity Create() public Entity Create()
{ {
return new Entity(idStorage.NextID()); return new Entity(NextID());
} }
public bool Exists(in Entity entity) public bool Exists(in Entity entity)
{ {
return idStorage.Taken(entity.ID); return Taken(entity.ID);
} }
public void Destroy(in Entity entity) public void Destroy(in Entity entity)
{ {
idStorage.Release(entity.ID); Release(entity.ID);
}
public void Serialize(EntityStorageState state)
{
state.NextID = nextID;
state.availableIDs.Clear();
foreach (var id in availableIDs)
{
state.availableIDs.Add(id);
}
}
public void Deserialize(EntityStorageState state)
{
nextID = state.NextID;
availableIDs.Clear();
availableIDHash.Clear();
foreach (var id in state.availableIDs)
{
availableIDs.Push(id);
availableIDHash.Add(id);
}
}
private int NextID()
{
if (availableIDs.Count > 0)
{
var id = availableIDs.Pop();
availableIDHash.Remove(id);
return id;
}
else
{
var id = nextID;
nextID += 1;
return id;
}
}
private bool Taken(int id)
{
return !availableIDHash.Contains(id) && id < nextID;
}
private void Release(int id)
{
availableIDs.Push(id);
availableIDHash.Add(id);
} }
} }
} }

View File

@ -1,39 +0,0 @@
using System.Collections.Generic;
namespace MoonTools.ECS
{
internal class IDStorage
{
private int nextID = 0;
private readonly Stack<int> availableIDs = new Stack<int>();
private readonly HashSet<int> availableIDHash = new HashSet<int>();
public int NextID()
{
if (availableIDs.Count > 0)
{
var id = availableIDs.Pop();
availableIDHash.Remove(id);
return id;
}
else
{
var id = nextID;
nextID += 1;
return id;
}
}
public bool Taken(int id)
{
return !availableIDHash.Contains(id) && id < nextID;
}
public void Release(int id)
{
availableIDs.Push(id);
availableIDHash.Add(id);
}
}
}

View File

@ -3,7 +3,7 @@ using System.Collections.Generic;
namespace MoonTools.ECS namespace MoonTools.ECS
{ {
public class ComponentDepotState internal class ComponentDepotState
{ {
public Dictionary<Type, ComponentStorageState> StorageStates = new Dictionary<Type, ComponentStorageState>(); public Dictionary<Type, ComponentStorageState> StorageStates = new Dictionary<Type, ComponentStorageState>();
public Dictionary<FilterSignature, IndexableSetState<int>> FilterStates = new Dictionary<FilterSignature, IndexableSetState<int>>(); public Dictionary<FilterSignature, IndexableSetState<int>> FilterStates = new Dictionary<FilterSignature, IndexableSetState<int>>();

View File

@ -2,8 +2,7 @@ using System.Collections.Generic;
namespace MoonTools.ECS namespace MoonTools.ECS
{ {
// for saving and loading component storage internal class ComponentStorageState
public class ComponentStorageState
{ {
public int Count; public int Count;
public Dictionary<int, int> EntityIdToStorageIndex; public Dictionary<int, int> EntityIdToStorageIndex;

View File

@ -0,0 +1,10 @@
using System.Collections.Generic;
namespace MoonTools.ECS
{
internal class EntityStorageState
{
public int NextID;
public List<int> availableIDs = new List<int>();
}
}

View File

@ -1,9 +1,8 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace MoonTools.ECS namespace MoonTools.ECS
{ {
public class IndexableSetState<T> where T : unmanaged internal class IndexableSetState<T> where T : unmanaged
{ {
public int Count; public int Count;
public Dictionary<T, int> Indices; public Dictionary<T, int> Indices;

14
src/State/WorldState.cs Normal file
View File

@ -0,0 +1,14 @@
namespace MoonTools.ECS
{
public class WorldState
{
internal ComponentDepotState ComponentDepotState;
internal EntityStorageState EntityStorageState;
public WorldState()
{
ComponentDepotState = new ComponentDepotState();
EntityStorageState = new EntityStorageState();
}
}
}

View File

@ -32,16 +32,21 @@
ComponentDepot.DisableSerialization<TComponent>(); ComponentDepot.DisableSerialization<TComponent>();
} }
public ComponentDepotState Serialize() public WorldState CreateState()
{ {
var state = ComponentDepot.CreateState(); return new WorldState();
ComponentDepot.Serialize(state);
return state;
} }
public void Deserialize(ComponentDepotState state) public void Serialize(WorldState state)
{ {
ComponentDepot.Deserialize(state); ComponentDepot.Serialize(state.ComponentDepotState);
EntityStorage.Serialize(state.EntityStorageState);
}
public void Deserialize(WorldState state)
{
ComponentDepot.Deserialize(state.ComponentDepotState);
EntityStorage.Deserialize(state.EntityStorageState);
} }
} }
} }