misc fixes
parent
001b6714cc
commit
8774314f62
|
@ -9,7 +9,10 @@ internal class Archetype
|
||||||
public ArchetypeSignature Signature;
|
public ArchetypeSignature Signature;
|
||||||
public NativeArray<Entity> Entities = new NativeArray<Entity>();
|
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;
|
public int Count => Entities.Count;
|
||||||
|
|
||||||
|
@ -25,13 +28,6 @@ internal class Archetype
|
||||||
return Entities.Count - 1;
|
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()
|
public void ClearAll()
|
||||||
{
|
{
|
||||||
for (int i = Entities.Count - 1; i >= 0; i -= 1)
|
for (int i = Entities.Count - 1; i >= 0; i -= 1)
|
||||||
|
|
|
@ -41,7 +41,7 @@ internal class ArchetypeSignature : IEquatable<ArchetypeSignature>
|
||||||
|
|
||||||
public void CopyTo(ArchetypeSignature other)
|
public void CopyTo(ArchetypeSignature other)
|
||||||
{
|
{
|
||||||
foreach (var id in other.Ids.AsSpan())
|
foreach (var id in Ids.AsSpan())
|
||||||
{
|
{
|
||||||
other.Ids.Add(id);
|
other.Ids.Add(id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ public unsafe class NativeArray<T> : IDisposable where T : unmanaged
|
||||||
// Fills gap by copying final element to the deleted index
|
// Fills gap by copying final element to the deleted index
|
||||||
public void Delete(int index)
|
public void Delete(int index)
|
||||||
{
|
{
|
||||||
if (Count > 1)
|
if (index != Count - 1)
|
||||||
{
|
{
|
||||||
NativeMemory.Copy(
|
NativeMemory.Copy(
|
||||||
(void*) (Elements + ((Count - 1) * ElementSize)),
|
(void*) (Elements + ((Count - 1) * ElementSize)),
|
||||||
|
|
|
@ -53,7 +53,7 @@ internal unsafe class NativeArray : IDisposable
|
||||||
// Fills gap by copying final element to the deleted index
|
// Fills gap by copying final element to the deleted index
|
||||||
public void Delete(int index)
|
public void Delete(int index)
|
||||||
{
|
{
|
||||||
if (Count > 1)
|
if (index != Count - 1)
|
||||||
{
|
{
|
||||||
NativeMemory.Copy(
|
NativeMemory.Copy(
|
||||||
(void*) (Elements + ((Count - 1) * ElementSize)),
|
(void*) (Elements + ((Count - 1) * ElementSize)),
|
||||||
|
|
|
@ -30,7 +30,6 @@ namespace MoonTools.ECS
|
||||||
|
|
||||||
public ref T Get<T>(in Entity entity) where T : unmanaged
|
public ref T Get<T>(in Entity entity) where T : unmanaged
|
||||||
{
|
{
|
||||||
|
|
||||||
return ref Components.Get<T>(EntityIDToStorageIndex[entity]);
|
return ref Components.Get<T>(EntityIDToStorageIndex[entity]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,17 +59,14 @@ public class Filter
|
||||||
// WARNING: this WILL crash if the index is out of range!
|
// WARNING: this WILL crash if the index is out of range!
|
||||||
public Entity NthEntity(int index)
|
public Entity NthEntity(int index)
|
||||||
{
|
{
|
||||||
var count = 0;
|
|
||||||
|
|
||||||
foreach (var archetype in Archetypes)
|
foreach (var archetype in Archetypes)
|
||||||
{
|
{
|
||||||
count += archetype.Count;
|
if (index < archetype.Count)
|
||||||
if (index < count)
|
|
||||||
{
|
{
|
||||||
return archetype.Entities[index];
|
return archetype.Entities[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
index -= count;
|
index -= archetype.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new InvalidOperationException("Filter index out of range!");
|
throw new InvalidOperationException("Filter index out of range!");
|
||||||
|
@ -135,12 +132,12 @@ public class Filter
|
||||||
|
|
||||||
// breadth-first search
|
// breadth-first search
|
||||||
// ignore excluded component edges
|
// 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);
|
Explored.Add(edge);
|
||||||
ArchetypeSearchQueue.Enqueue(edge.Add);
|
ArchetypeSearchQueue.Enqueue(edge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,4 +2,10 @@ using System;
|
||||||
|
|
||||||
namespace MoonTools.ECS;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
103
src/World.cs
103
src/World.cs
|
@ -90,6 +90,14 @@ namespace MoonTools.ECS
|
||||||
var entity = new Entity(EntityIdAssigner.Assign());
|
var entity = new Entity(EntityIdAssigner.Assign());
|
||||||
EntityIndex.Add(entity, new ArchetypeRecord(EmptyArchetype, EmptyArchetype.Count));
|
EntityIndex.Add(entity, new ArchetypeRecord(EmptyArchetype, EmptyArchetype.Count));
|
||||||
EmptyArchetype.Append(entity);
|
EmptyArchetype.Append(entity);
|
||||||
|
|
||||||
|
if (!EntityRelationIndex.ContainsKey(entity))
|
||||||
|
{
|
||||||
|
EntityRelationIndex.Add(entity, new IndexableSet<TypeId>());
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityTags[entity] = tag;
|
||||||
|
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,7 +185,7 @@ namespace MoonTools.ECS
|
||||||
|
|
||||||
if (!componentStorage.Set(entity, component))
|
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))
|
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 componentTypeId = TypeToId[typeof(T)];
|
||||||
var record = EntityIndex[entity];
|
var record = EntityIndex[entity];
|
||||||
var archetype = record.Archetype;
|
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;
|
return nextArchetype;
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var newRow = archetype.Transfer(record.Row, nextArchetype);
|
var nextSignature = new ArchetypeSignature(archetype.Signature.Count + 1);
|
||||||
EntityIndex[entity] = new ArchetypeRecord(nextArchetype, newRow);
|
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
|
// RELATIONS
|
||||||
|
|
Loading…
Reference in New Issue