MoonTools.ECS/src/Rev2/Snapshot.cs

231 lines
5.5 KiB
C#
Raw Normal View History

2023-10-25 01:44:41 +00:00
using System.Collections.Generic;
2023-10-30 23:25:33 +00:00
using System.Runtime.CompilerServices;
2023-10-30 19:11:50 +00:00
using MoonTools.ECS.Collections;
2023-10-25 01:44:41 +00:00
namespace MoonTools.ECS.Rev2;
public class Snapshot
{
private Dictionary<ArchetypeSignature, ArchetypeSnapshot> ArchetypeSnapshots =
new Dictionary<ArchetypeSignature, ArchetypeSnapshot>();
2023-10-30 23:25:33 +00:00
private Dictionary<Id, RelationSnapshot> RelationSnapshots =
new Dictionary<Id, RelationSnapshot>();
2023-10-30 19:11:50 +00:00
private Dictionary<Id, Record> EntityIndex = new Dictionary<Id, Record>();
2023-10-30 23:25:33 +00:00
private Dictionary<Id, IndexableSet<Id>> EntityRelationIndex =
new Dictionary<Id, IndexableSet<Id>>();
2023-10-30 19:11:50 +00:00
private IdAssigner IdAssigner = new IdAssigner();
2023-10-25 01:44:41 +00:00
public int Count
{
get
{
var count = 0;
foreach (var snapshot in ArchetypeSnapshots.Values)
{
count += snapshot.Count;
}
return count;
}
}
public void Restore(World world)
{
2023-10-30 19:11:50 +00:00
// restore archetype storage
2023-10-25 01:44:41 +00:00
foreach (var (archetypeSignature, archetypeSnapshot) in ArchetypeSnapshots)
{
var archetype = world.ArchetypeIndex[archetypeSignature];
2023-10-30 23:25:33 +00:00
archetypeSnapshot.Restore(archetype);
2023-10-25 01:44:41 +00:00
}
2023-10-30 19:11:50 +00:00
// restore entity index
world.EntityIndex.Clear();
foreach (var (id, record) in EntityIndex)
{
world.EntityIndex[id] = record;
}
// restore id assigner state
IdAssigner.CopyTo(world.IdAssigner);
2023-10-30 23:25:33 +00:00
// restore relation state
foreach (var (typeId, relationSnapshot) in RelationSnapshots)
{
var relationStorage = world.RelationIndex[typeId];
relationSnapshot.Restore(relationStorage);
}
// restore entity relation index state
// FIXME: arghhhh this is so slow
foreach (var (id, relationTypeSet) in EntityRelationIndex)
{
world.EntityRelationIndex[id].Clear();
foreach (var typeId in relationTypeSet)
{
world.EntityRelationIndex[id].Add(typeId);
}
}
2023-10-25 01:44:41 +00:00
}
2023-10-30 19:11:50 +00:00
public void Take(World world)
2023-10-25 01:44:41 +00:00
{
2023-10-30 19:11:50 +00:00
// copy id assigner state
world.IdAssigner.CopyTo(IdAssigner);
// copy entity index
EntityIndex.Clear();
foreach (var (id, record) in world.EntityIndex)
{
EntityIndex[id] = record;
}
// copy archetypes
foreach (var archetype in world.ArchetypeIndex.Values)
2023-10-25 01:44:41 +00:00
{
2023-10-30 19:11:50 +00:00
TakeArchetypeSnapshot(archetype);
2023-10-25 01:44:41 +00:00
}
2023-10-30 23:25:33 +00:00
// copy relations
foreach (var (typeId, relationStorage) in world.RelationIndex)
{
TakeRelationSnapshot(typeId, relationStorage);
}
// copy entity relation index
// FIXME: arghhhh this is so slow
foreach (var (id, relationTypeSet) in world.EntityRelationIndex)
{
if (!EntityRelationIndex.ContainsKey(id))
{
EntityRelationIndex.Add(id, new IndexableSet<Id>());
}
EntityRelationIndex[id].Clear();
foreach (var typeId in relationTypeSet)
{
EntityRelationIndex[id].Add(typeId);
}
}
2023-10-25 01:44:41 +00:00
}
2023-10-30 23:25:33 +00:00
private void TakeArchetypeSnapshot(Archetype archetype)
2023-10-25 01:44:41 +00:00
{
if (!ArchetypeSnapshots.TryGetValue(archetype.Signature, out var archetypeSnapshot))
{
archetypeSnapshot = new ArchetypeSnapshot(archetype.Signature);
ArchetypeSnapshots.Add(archetype.Signature, archetypeSnapshot);
}
archetypeSnapshot.Take(archetype);
}
2023-10-30 23:25:33 +00:00
private void TakeRelationSnapshot(Id typeId, RelationStorage relationStorage)
2023-10-25 01:44:41 +00:00
{
2023-10-30 23:25:33 +00:00
if (!RelationSnapshots.TryGetValue(typeId, out var snapshot))
{
snapshot = new RelationSnapshot(World.ElementSizes[typeId]);
RelationSnapshots.Add(typeId, snapshot);
}
snapshot.Take(relationStorage);
2023-10-25 01:44:41 +00:00
}
private class ArchetypeSnapshot
{
2023-10-31 18:10:42 +00:00
private readonly NativeArray[] ComponentColumns;
2023-10-30 19:11:50 +00:00
private readonly NativeArray<Id> RowToEntity;
2023-10-25 01:44:41 +00:00
2023-10-30 19:11:50 +00:00
public int Count => RowToEntity.Count;
2023-10-25 01:44:41 +00:00
public ArchetypeSnapshot(ArchetypeSignature signature)
{
2023-10-31 18:10:42 +00:00
ComponentColumns = new NativeArray[signature.Count];
2023-10-30 19:11:50 +00:00
RowToEntity = new NativeArray<Id>();
2023-10-25 01:44:41 +00:00
for (int i = 0; i < signature.Count; i += 1)
{
var componentId = signature[i];
2023-10-31 18:10:42 +00:00
ComponentColumns[i] = new NativeArray(World.ElementSizes[componentId]);
2023-10-25 01:44:41 +00:00
}
}
public void Take(Archetype archetype)
{
2023-10-30 19:11:50 +00:00
for (int i = 0; i < ComponentColumns.Length; i += 1)
2023-10-25 01:44:41 +00:00
{
archetype.ComponentColumns[i].CopyAllTo(ComponentColumns[i]);
}
2023-10-30 19:11:50 +00:00
archetype.RowToEntity.CopyTo(RowToEntity);
2023-10-25 01:44:41 +00:00
}
public void Restore(Archetype archetype)
{
// Copy all component data
2023-10-30 19:11:50 +00:00
for (int i = 0; i < ComponentColumns.Length; i += 1)
2023-10-25 01:44:41 +00:00
{
ComponentColumns[i].CopyAllTo(archetype.ComponentColumns[i]);
}
2023-10-30 19:11:50 +00:00
RowToEntity.CopyTo(archetype.RowToEntity);
2023-10-25 01:44:41 +00:00
}
}
2023-10-30 23:25:33 +00:00
private class RelationSnapshot
{
2023-10-31 18:10:42 +00:00
private NativeArray Relations;
private NativeArray RelationDatas;
2023-10-30 23:25:33 +00:00
public RelationSnapshot(int elementSize)
{
2023-10-31 18:10:42 +00:00
Relations = new NativeArray(Unsafe.SizeOf<(Id, Id)>());
RelationDatas = new NativeArray(elementSize);
2023-10-30 23:25:33 +00:00
}
public void Take(RelationStorage relationStorage)
{
relationStorage.relations.CopyAllTo(Relations);
relationStorage.relationDatas.CopyAllTo(RelationDatas);
}
public void Restore(RelationStorage relationStorage)
{
relationStorage.Clear();
Relations.CopyAllTo(relationStorage.relations);
RelationDatas.CopyAllTo(relationStorage.relationDatas);
for (int index = 0; index < Relations.Count; index += 1)
{
var relation = Relations.Get<(Id, Id)>(index);
relationStorage.indices[relation] = index;
relationStorage.indices[relation] = index;
if (!relationStorage.outRelations.ContainsKey(relation.Item1))
{
relationStorage.outRelations[relation.Item1] =
relationStorage.AcquireHashSetFromPool();
}
relationStorage.outRelations[relation.Item1].Add(relation.Item2);
if (!relationStorage.inRelations.ContainsKey(relation.Item2))
{
relationStorage.inRelations[relation.Item2] =
relationStorage.AcquireHashSetFromPool();
}
relationStorage.inRelations[relation.Item2].Add(relation.Item1);
}
}
}
2023-10-25 01:44:41 +00:00
}