diff --git a/plugins/TinyEcs.Plugins/Relationship.cs b/plugins/TinyEcs.Plugins/Relationship.cs index 8d0c601..f123e0b 100644 --- a/plugins/TinyEcs.Plugins/Relationship.cs +++ b/plugins/TinyEcs.Plugins/Relationship.cs @@ -2,7 +2,10 @@ namespace TinyEcs; -public struct Relationship +public readonly struct Hierarchy { } + + +public struct Relationship where T : struct { public int Count; public EcsID First; @@ -10,13 +13,13 @@ public struct Relationship public EcsID Next; public EcsID Prev; - public readonly RelationshipIterator Children(World world) => new (world, First); + public readonly RelationshipIterator Children(World world) => new (world, First); } -public readonly struct Parent { } -public readonly struct Child { } +public readonly struct Parent where T : struct { } +public readonly struct Child where T : struct { } -public ref struct RelationshipIterator +public ref struct RelationshipIterator where T : struct { private readonly World _world; private EcsID _currentEntity, _next; @@ -35,12 +38,12 @@ public bool MoveNext() _currentEntity = _next; if (_next != 0) - _next = _world.Get(_next).Next; + _next = _world.Get>(_next).Next; return _currentEntity != 0; } - public readonly RelationshipIterator GetEnumerator() => this; + public readonly RelationshipIterator GetEnumerator() => this; } public static class RelationshipPlugin @@ -49,63 +52,74 @@ public static class RelationshipPlugin internal static void ModuleInit() { World.OnPluginInitialization += world => { - world.Component(); - world.Component(); - world.Component(); - world.OnEntityDeleted += e => { - if (e.Has()) - { - e.World.Merge(); - - foreach (var childId in e.Children()) - { - e.World.DeferredEntity(childId).Delete(); - } - - e.World.Merge(); - } + world.Component>(); + world.Component>(); + world.Component>(); + world.BindDeletion(); + }; + } - if (e.Has()) + private static void BindDeletion(this World world) where T : struct + { + world.OnEntityDeleted += e => { + if (e.Has>()) + { + var first = e.Get>().First; + while (first != 0) { - ref var rel = ref e.Get(); - if (rel.Parent != 0 && e.World.Exists(rel.Parent)) - e.World.Entity(rel.Parent).RemoveChild(e); + var next = e.World.Get>(first).Next; + e.World.Delete(first); + first = next; } - }; + } + + if (e.Has>()) + { + ref var rel = ref e.Get>(); + if (rel.Parent != 0 && e.World.Exists(rel.Parent)) + e.World.Entity(rel.Parent).RemoveChild(e); + } }; } - public static void AddChild(this EntityView entity, EcsID child) - => entity.World.AddChild(entity.ID, child); + public static void AddChild(this EntityView entity, EcsID child) where T : struct + => entity.World.AddChild(entity.ID, child); - public static void RemoveChild(this EntityView entity, EcsID child) - => entity.World.RemoveChild(entity.ID, child); + public static void RemoveChild(this EntityView entity, EcsID child) where T : struct + => entity.World.RemoveChild(entity.ID, child); - public static void ClearChildren(this EntityView entity) - => entity.World.ClearChildren(entity.ID); + public static void ClearChildren(this EntityView entity) where T : struct + => entity.World.ClearChildren(entity.ID); - public static RelationshipIterator Children(this EntityView entity) + public static RelationshipIterator Children(this EntityView entity) where T : struct { - if (!entity.Has()) + if (!entity.Has>()) return default; - return entity.Get().Children(entity.World); + return entity.Get>().Children(entity.World)!; } - public static void AddChild(this World world, EcsID parentId, EcsID childId) + public static void AddChild(this World world, EcsID parentId, EcsID childId) where T : struct { - if (!world.Has(parentId)) + var hierarchy = world.Entity(); + if (!hierarchy.Has()) + { + hierarchy.Set(); + world.BindDeletion(); + } + + if (!world.Has>(parentId)) { - world.Set(parentId, new Relationship()); + world.Set(parentId, new Relationship()); } - if (!world.Has(childId)) + if (!world.Has>(childId)) { - world.Set(childId, new Relationship()); + world.Set(childId, new Relationship()); } - ref var parentRelationship = ref world.Get(parentId); - ref var childRelationship = ref world.Get(childId); + ref var parentRelationship = ref world.Get>(parentId); + ref var childRelationship = ref world.Get>(childId); // Update child's parent childRelationship.Parent = parentId; @@ -119,34 +133,34 @@ public static void AddChild(this World world, EcsID parentId, EcsID childId) { // Traverse to the end of the children list var current = parentRelationship.First; - while (world.Get(current).Next != 0) + while (world.Get>(current).Next != 0) { - current = world.Get(current).Next; + current = world.Get>(current).Next; } // Add the child at the end - ref var lastRelationship = ref world.Get(current); + ref var lastRelationship = ref world.Get>(current); lastRelationship.Next = childId; childRelationship.Prev = current; parentRelationship.Count++; } - world.Set(parentId); - world.Set(childId); + world.Set>(parentId); + world.Set>(childId); } - public static void RemoveChild(this World world, EcsID parentId, EcsID childId) + public static void RemoveChild(this World world, EcsID parentId, EcsID childId) where T : struct { - if (!world.Has(parentId)) + if (!world.Has>(parentId)) return; - ref var parentRelationship = ref world.Get(parentId); - ref var childRelationship = ref world.Get(childId); + ref var parentRelationship = ref world.Get>(parentId); + ref var childRelationship = ref world.Get>(childId); if (childRelationship.Prev != 0) { // Update previous sibling's next pointer - ref var prevRelationship = ref world.Get(childRelationship.Prev); + ref var prevRelationship = ref world.Get>(childRelationship.Prev); prevRelationship.Next = childRelationship.Next; } else @@ -158,7 +172,7 @@ public static void RemoveChild(this World world, EcsID parentId, EcsID childId) if (childRelationship.Next != 0) { // Update next sibling's previous pointer - ref var nextRelationship = ref world.Get(childRelationship.Next); + ref var nextRelationship = ref world.Get>(childRelationship.Next); nextRelationship.Prev = childRelationship.Prev; } @@ -168,33 +182,33 @@ public static void RemoveChild(this World world, EcsID parentId, EcsID childId) childRelationship.Prev = 0; parentRelationship.Count--; - world.Unset(childId); - world.Unset(childId); + world.Unset>(childId); + world.Unset>(childId); if (parentRelationship.Count <= 0) { - world.Unset(parentId); + world.Unset>(parentId); if (parentRelationship.Parent == 0) - world.Unset(parentId); + world.Unset>(parentId); } } - public static void ClearChildren(this World world, EcsID parentId) + public static void ClearChildren(this World world, EcsID parentId) where T : struct { - if (!world.Has(parentId)) + if (!world.Has>(parentId)) return; - ref var parentRelationship = ref world.Get(parentId); + ref var parentRelationship = ref world.Get>(parentId); var currentChild = parentRelationship.First; while (currentChild != 0) { - var nextChild = world.Get(currentChild).Next; - world.RemoveChild(parentId, currentChild); + var nextChild = world.Get>(currentChild).Next; + world.RemoveChild(parentId, currentChild); currentChild = nextChild; } - world.Unset(parentId); + world.Unset>(parentId); } } diff --git a/samples/MyBattleground/Program.cs b/samples/MyBattleground/Program.cs index 56cf9ff..c5ff909 100644 --- a/samples/MyBattleground/Program.cs +++ b/samples/MyBattleground/Program.cs @@ -12,6 +12,13 @@ .Set(new Position() {X = 2}) .Set(new Velocity()); + +var rabbit = ecs.Entity(); +var eats = ecs.Entity(); +var carrots = ecs.Entity(); +var grass = ecs.Entity(); + + e.Disable(); var enabled = e.IsEnabled(); e.Disable(); @@ -36,25 +43,36 @@ var child3 = ecs.Entity("child 2"); -e.AddChild(child); -e.AddChild(child2); -child2.AddChild(child3); +e.AddChild(child); +e.AddChild(child2); +child2.AddChild(child3); + + +e.AddChild(child2); +e.AddChild(child3); + +child2.Delete(); + +foreach (var childId in e.Children()) +{ + +} -foreach (var childId in e.Children()) +foreach (var childId in e.Children()) { } -ecs.Filter<(With, With)>().Query((EntityView entity, ref Relationship relation) => { +ecs.Filter<(With>, With>)>().Query((EntityView entity, ref Relationship relation) => { Console.WriteLine("im [{0}] a child of {1}, but also having {2} children", entity.Name(), ecs.Entity(relation.Parent).Name(), relation.Count); }); Console.WriteLine(); -ecs.Filter>().Query((EntityView entity, ref Relationship relation) => { +ecs.Filter>>().Query((EntityView entity, ref Relationship relation) => { Console.WriteLine("parent {0} has {1} children", entity.Name(), relation.Count); - foreach (var id in entity.Children()) + foreach (var id in entity.Children()) { Console.WriteLine("\tChild: {0}", ecs.Entity(id).Name()); } @@ -62,15 +80,15 @@ Console.WriteLine(); -e.RemoveChild(child); -ecs.Filter>().Query((EntityView entity, ref Relationship relation) => { +e.RemoveChild(child); +ecs.Filter>>().Query((EntityView entity, ref Relationship relation) => { Console.WriteLine("parent {0} has {1} children", entity.Name(), relation.Count); }); Console.WriteLine(); -child2.RemoveChild(child3); -ecs.Filter>().Query((EntityView entity, ref Relationship relation) => { +child2.RemoveChild(child3); +ecs.Filter>>().Query((EntityView entity, ref Relationship relation) => { Console.WriteLine("parent {0} has {1} children", entity.Name(), relation.Count); }); @@ -85,10 +103,10 @@ { var c = ecs.Entity(); Console.WriteLine("Add {0}", c.ID); - e.AddChild(c); + e.AddChild(c); } -foreach (var childId in e.Children()) +foreach (var childId in e.Children()) { Console.WriteLine("child {0}", childId); } diff --git a/src/Archetype.cs b/src/Archetype.cs index 9112e2d..4b0684b 100644 --- a/src/Archetype.cs +++ b/src/Archetype.cs @@ -330,7 +330,7 @@ internal int FindMatch(ReadOnlySpan searching) ref readonly var current = ref currents[i]; ref readonly var search = ref searching[j]; - if (current.ID.CompareTo(search.ID) == 0) + if (_comparer.Compare(current.ID, search.ID) == 0) { if (search.Op != TermOp.With) return -1; diff --git a/src/ComponentComparer.cs b/src/ComponentComparer.cs index 0d1003f..536d2de 100644 --- a/src/ComponentComparer.cs +++ b/src/ComponentComparer.cs @@ -27,18 +27,18 @@ public int Compare(Term x, Term y) public static int CompareTerms(World world, ulong a, ulong b) { - //if (IDOp.IsPair(a) && IDOp.IsPair(b)) - //{ - // if (IDOp.GetPairFirst(a) == IDOp.GetPairFirst(b)) - // { - // var secondY = IDOp.GetPairSecond(b); - - // if (secondY == Lookup.Entity.Component.ID) - // { - // return 0; - // } - // } - //} + // if (IDOp.IsPair(a) && IDOp.IsPair(b)) + // { + // if (IDOp.GetPairFirst(a) == IDOp.GetPairFirst(b)) + // { + // var secondY = IDOp.GetPairSecond(b); + + // if (secondY == ulong.MaxValue) + // { + // return 0; + // } + // } + // } return a.CompareTo(b); } diff --git a/src/World.cs b/src/World.cs index c5f1c97..784e44c 100644 --- a/src/World.cs +++ b/src/World.cs @@ -162,7 +162,7 @@ internal EntityView NewEmpty(ulong id = 0) internal ref EcsRecord GetRecord(EcsID id) { ref var record = ref _entities.Get(id); - EcsAssert.Assert(!Unsafe.IsNullRef(ref record)); + EcsAssert.Assert(!Unsafe.IsNullRef(ref record), $"entity {id} is dead or doesn't exist!"); return ref record; }