misc fixes

pull/6/head
cosmonaut 2023-11-03 15:39:30 -07:00
parent 001b6714cc
commit 8774314f62
8 changed files with 91 additions and 54 deletions

View File

@ -9,7 +9,10 @@ internal class Archetype
public ArchetypeSignature Signature;
public NativeArray<Entity> Entities = new NativeArray<Entity>();
public SortedDictionary<TypeId, ArchetypeEdge> Edges = new SortedDictionary<TypeId, ArchetypeEdge>();
public SortedDictionary<TypeId, Archetype> AddEdges =
new SortedDictionary<TypeId, Archetype>();
public SortedDictionary<TypeId, Archetype> RemoveEdges =
new SortedDictionary<TypeId, Archetype>();
public int Count => Entities.Count;
@ -25,13 +28,6 @@ internal class Archetype
return Entities.Count - 1;
}
public int Transfer(int row, Archetype transferTo)
{
var newIndex = transferTo.Append(Entities[row]);
Entities.Delete(row);
return newIndex;
}
public void ClearAll()
{
for (int i = Entities.Count - 1; i >= 0; i -= 1)

View File

@ -41,7 +41,7 @@ internal class ArchetypeSignature : IEquatable<ArchetypeSignature>
public void CopyTo(ArchetypeSignature other)
{
foreach (var id in other.Ids.AsSpan())
foreach (var id in Ids.AsSpan())
{
other.Ids.Add(id);
}

View File

@ -69,7 +69,7 @@ public unsafe class NativeArray<T> : IDisposable where T : unmanaged
// Fills gap by copying final element to the deleted index
public void Delete(int index)
{
if (Count > 1)
if (index != Count - 1)
{
NativeMemory.Copy(
(void*) (Elements + ((Count - 1) * ElementSize)),

View File

@ -53,7 +53,7 @@ internal unsafe class NativeArray : IDisposable
// Fills gap by copying final element to the deleted index
public void Delete(int index)
{
if (Count > 1)
if (index != Count - 1)
{
NativeMemory.Copy(
(void*) (Elements + ((Count - 1) * ElementSize)),

View File

@ -30,7 +30,6 @@ namespace MoonTools.ECS
public ref T Get<T>(in Entity entity) where T : unmanaged
{
return ref Components.Get<T>(EntityIDToStorageIndex[entity]);
}

View File

@ -59,17 +59,14 @@ public class Filter
// WARNING: this WILL crash if the index is out of range!
public Entity NthEntity(int index)
{
var count = 0;
foreach (var archetype in Archetypes)
{
count += archetype.Count;
if (index < count)
if (index < archetype.Count)
{
return archetype.Entities[index];
}
index -= count;
index -= archetype.Count;
}
throw new InvalidOperationException("Filter index out of range!");
@ -135,12 +132,12 @@ public class Filter
// breadth-first search
// ignore excluded component edges
foreach (var (componentId, edge) in current.Edges)
foreach (var (componentId, edge) in current.AddEdges)
{
if (!Explored.Contains(edge.Add) && !filter.Excluded.Contains(componentId))
if (!filter.Excluded.Contains(componentId))
{
Explored.Add(edge.Add);
ArchetypeSearchQueue.Enqueue(edge.Add);
Explored.Add(edge);
ArchetypeSearchQueue.Enqueue(edge);
}
}
}

View File

@ -2,4 +2,10 @@ using System;
namespace MoonTools.ECS;
public readonly record struct TypeId(uint Value);
public readonly record struct TypeId(uint Value) : IComparable<TypeId>
{
public int CompareTo(TypeId other)
{
return Value.CompareTo(other.Value);
}
}

View File

@ -90,6 +90,14 @@ namespace MoonTools.ECS
var entity = new Entity(EntityIdAssigner.Assign());
EntityIndex.Add(entity, new ArchetypeRecord(EmptyArchetype, EmptyArchetype.Count));
EmptyArchetype.Append(entity);
if (!EntityRelationIndex.ContainsKey(entity))
{
EntityRelationIndex.Add(entity, new IndexableSet<TypeId>());
}
EntityTags[entity] = tag;
return entity;
}
@ -177,7 +185,7 @@ namespace MoonTools.ECS
if (!componentStorage.Set(entity, component))
{
UpdateArchetype<T>(entity, true);
TransferArchetype(entity, FindArchetypeByAdd<T>(entity));
}
}
@ -187,48 +195,79 @@ namespace MoonTools.ECS
if (componentStorage.Remove(entity))
{
UpdateArchetype<T>(entity, false);
TransferArchetype(entity, FindArchetypeByRemove<T>(entity));
}
}
private void UpdateArchetype<T>(in Entity entity, bool insert)
private Archetype FindArchetypeByAdd<T>(in Entity entity)
{
Archetype? nextArchetype;
var componentTypeId = TypeToId[typeof(T)];
var record = EntityIndex[entity];
var archetype = record.Archetype;
if (archetype.Edges.TryGetValue(TypeToId[typeof(T)], out var edge))
if (archetype.AddEdges.TryGetValue(componentTypeId, out var nextArchetype))
{
nextArchetype = insert ? edge.Add : edge.Remove;
}
else
{
var nextSignature = new ArchetypeSignature(archetype.Signature.Count + 1);
archetype.Signature.CopyTo(nextSignature);
if (insert)
{
nextSignature.Insert(componentTypeId);
}
else
{
nextSignature.Remove(componentTypeId);
}
if (!ArchetypeIndex.TryGetValue(nextSignature, out nextArchetype))
{
nextArchetype = CreateArchetype(nextSignature);
}
var newEdge = new ArchetypeEdge(nextArchetype, archetype);
archetype.Edges.Add(componentTypeId, newEdge);
nextArchetype.Edges.Add(componentTypeId, newEdge);
return nextArchetype;
}
var newRow = archetype.Transfer(record.Row, nextArchetype);
EntityIndex[entity] = new ArchetypeRecord(nextArchetype, newRow);
var nextSignature = new ArchetypeSignature(archetype.Signature.Count + 1);
archetype.Signature.CopyTo(nextSignature);
nextSignature.Insert(componentTypeId);
if (!ArchetypeIndex.TryGetValue(nextSignature, out nextArchetype))
{
nextArchetype = CreateArchetype(nextSignature);
}
archetype.AddEdges.Add(componentTypeId, nextArchetype);
nextArchetype.RemoveEdges.Add(componentTypeId, archetype);
return nextArchetype;
}
private Archetype FindArchetypeByRemove<T>(in Entity entity)
{
var componentTypeId = TypeToId[typeof(T)];
var record = EntityIndex[entity];
var archetype = record.Archetype;
if (archetype.RemoveEdges.TryGetValue(componentTypeId, out var nextArchetype))
{
return nextArchetype;
}
var nextSignature = new ArchetypeSignature(archetype.Signature.Count + 1);
archetype.Signature.CopyTo(nextSignature);
nextSignature.Remove(componentTypeId);
if (!ArchetypeIndex.TryGetValue(nextSignature, out nextArchetype))
{
nextArchetype = CreateArchetype(nextSignature);
}
archetype.RemoveEdges.Add(componentTypeId, nextArchetype);
nextArchetype.AddEdges.Add(componentTypeId, archetype);
return nextArchetype;
}
private void TransferArchetype(in Entity entity, Archetype nextArchetype)
{
var record = EntityIndex[entity];
var archetype = record.Archetype;
var row = record.Row;
// fill the gap
if (row != archetype.Count - 1)
{
var lastEntity = archetype.Entities[archetype.Count - 1];
archetype.Entities[row] = lastEntity;
EntityIndex[lastEntity] = new ArchetypeRecord(archetype, row);
}
archetype.Entities.RemoveLastElement();
nextArchetype.Entities.Append(entity);
EntityIndex[entity] = new ArchetypeRecord(nextArchetype, nextArchetype.Count - 1);
}
// RELATIONS