diff --git a/src/Entity.bf b/src/Entity.bf new file mode 100644 index 0000000..0a0da92 --- /dev/null +++ b/src/Entity.bf @@ -0,0 +1,31 @@ +namespace Theater_ECS; + +using System; + +public struct Entity : uint32 +{ + public static readonly Entity Null => 0x000FFFFF; + public static readonly uint32 VersionMask => 0xFFF00000; + public static readonly uint32 IndexMask => 0x000FFFFF; + public static readonly uint8 VersionOffset => 20; + + public uint32 Index => (.)this & IndexMask; + public uint32 Version => (.)(this & VersionMask) >> VersionOffset + public Entity Next => .(Index, Version + 1); + + public this() + { + this = Entity.Null; + }; + + public this(uint32 index, uint32 version) + { + this = (index & IndexMask) | ((version << VersionOffset) & VersionMask); + + } + + public override void ToString(String strBuffer) + { + strBuffer.Append(scope $"{Index}:{Version}"); + } +} \ No newline at end of file diff --git a/src/EntityRegister.bf b/src/EntityRegister.bf index 1fc686a..dde6f29 100644 --- a/src/EntityRegister.bf +++ b/src/EntityRegister.bf @@ -3,35 +3,6 @@ namespace Theater_ECS; using System; using System.Collections; -static -{ - - public struct Entity : uint32 - { - public static readonly Entity Null => 0xFFFFF; - public static readonly uint32 VersionMask => 0xFFF00000; - public static readonly uint32 IndexMask => 0x000FFFFF; - public static readonly uint8 VersionOffset => 20; - - public uint32 Index => (.)this & IndexMask; - public uint32 Version => (.)(this & VersionMask) >> VersionOffset - public Entity Next => .(Index, Version + 1); - - public this() {}; - - public this(uint32 index, uint32 version) - { - this = (index & IndexMask) | ((version << VersionOffset) & VersionMask); - - } - - public override void ToString(String strBuffer) - { - strBuffer.Append(scope $"{Index}:{Version}"); - } - } -} - class EntityRegister { private List _entities = new .() ~ delete _; @@ -39,7 +10,7 @@ class EntityRegister private Entity _next = .Null; - public Entity CreateEntity() + public Entity Create() { if(_available == 0) { @@ -59,7 +30,7 @@ class EntityRegister } } - public void RemoveEntity(Entity e) + public void Remove(Entity e) { let temp = _next; _next = .(e.Index, 255); diff --git a/src/Example/MoverSystem.bf b/src/Example/MoverSystem.bf index e02cec7..7777556 100644 --- a/src/Example/MoverSystem.bf +++ b/src/Example/MoverSystem.bf @@ -7,7 +7,7 @@ class MoverSystem : System [SystemMethod("MoveItems", typeof(Velocity), typeof(Position))] public void MoveItems(ref Velocity v,ref Position p) { - //p.x = v.x + p.x; - //p.y = v.y = p.y; + p.x = v.x + p.x; + p.y = v.y = p.y; } } \ No newline at end of file diff --git a/src/Example/Program.bf b/src/Example/Program.bf index c20d2a4..6cd5acb 100644 --- a/src/Example/Program.bf +++ b/src/Example/Program.bf @@ -11,68 +11,38 @@ class Program public static void Main() { - /* - Entity e = Entity(45454, 797979790); - Console.WriteLine(e); - Console.Read(); - - EntityRegister r = scope .(); - while(true) - { - Console.WriteLine(scope $"Next: {r.[Friend]_next}"); - for(var i in r.[Friend]_entities) - Console.WriteLine(i); - var l = Console.ReadLine(.. scope .()); - - Console.Clear(); - - if(l == "c") - Console.WriteLine(r.CreateEntity()); - else if(l == "d") - r.RemoveEntity(.((.)gRand.Next(0 , r.[Friend]_entities.Count), 0)); - Console.WriteLine(); - } - */ - - ECS ecs = scope .(); - var pos = ecs.RegisterComponent(100); - //var waste = ecs.RegisterComponent(100); - var vel = ecs.RegisterComponent(100); - - - List entities = scope .(); - for(int i < 500000) - entities.Add(ecs.CreateEntity()); - - for(var i in entities) - *(Position*)ecs.AddComponentToEntity(i, pos).Value = .(); - - for(var i in entities) - *(Velocity*)ecs.AddComponentToEntity(i, vel).Value = .(); - - /* - for(var i in entities) - if(gRand.NextI32() % 2 == 1) - *(waste*)ecs.AddComponentToEntity(i, waste).Value = .(); - */ - - MoverSystem s = scope .(); - s.IntializeSystem(ecs); - - System.Diagnostics.Stopwatch watch = scope .(); - for(int a < 10) - { - watch.Start(); - for(int i < 10) + EntityRegister e = scope .(); + PagedSparseSet p = scope .(); + PagedSparseSet v =scope .(); + List es = new .(); + defer delete es; + for(int i < 1000000) { - - s.RunSystem(ecs); - + var ent = e.Create(); + p.Add(ent, .()); + v.Add(ent, .()); + es.Add(ent); + } + + System.Diagnostics.Stopwatch watch = scope .(); + for(int a < 10) + { + watch.Start(); + for(int i < 10) + { + var pos = p.GetAll(); + var vel = v.GetAll(); + + for(var ps in pos) + { + ps.1.x += vel[@ps.Index].1.x; + ps.1.y += vel[@ps.Index].1.y; + } + } + Console.WriteLine(scope $"{watch.ElapsedMilliseconds}ms"); + watch.Stop(); + watch.Reset(); } - Console.WriteLine(scope $"{watch.ElapsedMilliseconds}ms"); - watch.Stop(); - watch.Reset(); - } Console.Read(); } } diff --git a/src/PagedSparseSet.bf b/src/PagedSparseSet.bf index 55a004e..d4e04b7 100644 --- a/src/PagedSparseSet.bf +++ b/src/PagedSparseSet.bf @@ -1,5 +1,77 @@ namespace Theater_ECS; -class PagedSparseSet +using System; +using System.Collections; + +class PagedSparseSet where T : struct { + public const uint32 PageSize = 4096; + + private List> _sparse = new .()~ DeleteContainerAndItems!(_); + private List<(Entity, T)> _packed = new .() ~ delete _; + private List _packedEntities = new .() ~ delete _; + + public (Entity, T) this[Entity e] + { + public get => _packed[_sparse[e.Index/PageSize][e.Index % PageSize].Index]; + } + + public bool Contains(Entity e) + { + return _sparse[e.Index/PageSize][e.Index % PageSize] != Entity.Null; + } + + public void Add(Entity e, T toAdd) + { + EnsureLoadedPage(e.Index/PageSize); + _packed.Add((e, toAdd)); + _sparse[e.Index/PageSize][e.Index % PageSize] = (.)_packed.Count-1; + } + + public void Remove(Entity e) + { + EnsurePage(e.Index/PageSize); + if(_sparse[e.Index/PageSize] == null) + return; + + let toRm = _packed[_sparse[e.Index/PageSize][e.Index % PageSize].Index]; + let b = _packed.Back; + _packed[_sparse[e.Index/PageSize][e.Index % PageSize].Index] = b; + _packed.Back = toRm; + + _sparse[b.0.Index/PageSize][b.0.Index % PageSize] = Entity(e.Index, b.0.Version); + _sparse[e.Index/PageSize][e.Index % PageSize] = Entity.Null; + + _packed.PopBack(); + } + + public T* Get(Entity e) + { + return &_packed[_sparse[e.Index/PageSize][e.Index % PageSize].Index].1; + } + + public Span<(Entity, T)> GetAll() + { + return _packed; + } + + ///Ensure that a page exist and is loaded + public void EnsureLoadedPage(uint32 page) + { + EnsurePage(page); + if(_sparse[page] == null) + { + _sparse[page] = new List(PageSize); + _sparse[page].[Friend]Count = 4096; + _sparse[page].SetAll(Entity.Null); + + } + } + + ///Ensure that a page exists, it might be null though + private void EnsurePage(uint32 page) + { + while(_sparse.Count < page+1) + _sparse.Add(null); + } } \ No newline at end of file diff --git a/src/World.bf b/src/World.bf new file mode 100644 index 0000000..098b05c --- /dev/null +++ b/src/World.bf @@ -0,0 +1,12 @@ +namespace Theater_ECS; + +using System; +using System.Collections; + +class World +{ + EntityRegister Registry = new .() ~ delete _; + + private Dictionary _components = new .() ~ delete _; + private List _componentStorage = new .() ~ DeleteContainerAndDisposeItems!(_); +} \ No newline at end of file