diff --git a/src/Common.meta b/src/Builtin.meta similarity index 77% rename from src/Common.meta rename to src/Builtin.meta index 754906b..d66a065 100644 --- a/src/Common.meta +++ b/src/Builtin.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 88f41ce69c4d95c47aefc4360c26874f +guid: 38d25d74b63bca04484cf081895872f0 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/src/Common/EcsEdgeWorld.cs b/src/Builtin/EcsEdgeWorld.cs similarity index 100% rename from src/Common/EcsEdgeWorld.cs rename to src/Builtin/EcsEdgeWorld.cs diff --git a/src/Common/EcsEdgeWorld.cs.meta b/src/Builtin/EcsEdgeWorld.cs.meta similarity index 100% rename from src/Common/EcsEdgeWorld.cs.meta rename to src/Builtin/EcsEdgeWorld.cs.meta diff --git a/src/Builtin/HierarchyTag.cs b/src/Builtin/HierarchyTag.cs new file mode 100644 index 0000000..9934c9a --- /dev/null +++ b/src/Builtin/HierarchyTag.cs @@ -0,0 +1,4 @@ +namespace DCFApixels.DragonECS +{ + public struct ChildOf : IEcsTagComponent { } +} diff --git a/src/Builtin/HierarchyTag.cs.meta b/src/Builtin/HierarchyTag.cs.meta new file mode 100644 index 0000000..3f79036 --- /dev/null +++ b/src/Builtin/HierarchyTag.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1de8d8a49b0d49640847d1cec330fc4b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Common/RelationTargets.cs b/src/Common/RelationTargets.cs deleted file mode 100644 index bcd3871..0000000 --- a/src/Common/RelationTargets.cs +++ /dev/null @@ -1,30 +0,0 @@ -namespace DCFApixels.DragonECS -{ - public readonly struct RelationTargets - { - public static readonly RelationTargets Empty = new RelationTargets(); - public readonly int entity; - public readonly int otherEntity; - - public bool IsEmpty => entity == 0 && otherEntity == 0; - - public RelationTargets(int entity, int otherEntity) - { - this.entity = entity; - this.otherEntity = otherEntity; - } - - public override bool Equals(object obj) - { - return obj is RelationTargets targets && - entity == targets.entity && - otherEntity == targets.otherEntity; - } - public override int GetHashCode() => ~entity ^ otherEntity; - public override string ToString() => $"rel({entity}, {otherEntity})"; - - - public static bool operator ==(RelationTargets a, RelationTargets b) => (a.entity == b.entity && a.otherEntity == b.otherEntity); - public static bool operator !=(RelationTargets a, RelationTargets b) => a.entity != b.entity || a.otherEntity != b.otherEntity; - } -} \ No newline at end of file diff --git a/src/EcsEdge.cs b/src/EcsEdge.cs index d5811fa..89f3ed9 100644 --- a/src/EcsEdge.cs +++ b/src/EcsEdge.cs @@ -26,15 +26,15 @@ namespace DCFApixels.DragonECS public EcsWorld OtherWorld => _otherWorld; public EcsEdgeWorld EdgeWorld => _edgeWorld; - public bool IsSolo => _world == _otherWorld; + public bool IsLoop => _world == _otherWorld; - internal EcsEdge(EcsWorld world, EcsWorld otherWorld, EcsEdgeWorld relationWorld) + internal EcsEdge(EcsWorld world, EcsWorld otherWorld, EcsEdgeWorld edgeWorld) { - _edgeWorld = relationWorld; + _edgeWorld = edgeWorld; _world = world; _otherWorld = otherWorld; - _relationTargets = new RelationTargets[relationWorld.Capacity]; + _relationTargets = new RelationTargets[edgeWorld.Capacity]; _edgeWorld.AddListener(worldEventListener: this); _edgeWorld.AddListener(entityEventListener: this); @@ -44,9 +44,9 @@ namespace DCFApixels.DragonECS } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref readonly RelationTargets GetRelationTargets(int relationEntityID) + public ref readonly RelationTargets GetRelationTargets(int arcEntityID) { - return ref _relationTargets[relationEntityID]; + return ref _relationTargets[arcEntityID]; } #region Methods @@ -149,30 +149,48 @@ namespace DCFApixels.DragonECS #endregion #region Orientation - public readonly struct ForwardOrientation + public readonly struct ForwardOrientation : IEcsEdgeOrientation { private readonly EcsEdge _source; + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal ForwardOrientation(EcsEdge source) => _source = source; + [MethodImpl(MethodImplOptions.AggressiveInlining)] public int New(int entityID, int otherEntityID) => _source.NewRelation(entityID, otherEntityID); - public void Bind(int relationEntityID, int entityID, int otherEntityID) => _source.BindRelation(relationEntityID, entityID, otherEntityID); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Bind(int arcEntityID, int entityID, int otherEntityID) => _source.BindRelation(arcEntityID, entityID, otherEntityID); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Has(int entityID, int otherEntityID) => _source.HasRelation(entityID, otherEntityID); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public int Get(int entityID, int otherEntityID) => _source.GetRelation(entityID, otherEntityID); - public bool TryGet(int entityID, int otherEntityID, out int relationEntityID) => _source.TryGetRelation(entityID, otherEntityID, out relationEntityID); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGet(int entityID, int otherEntityID, out int arcEntityID) => _source.TryGetRelation(entityID, otherEntityID, out arcEntityID); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public IdsLinkedList.Span Get(int entityID) => _source._basket.GetSpanFor(entityID); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public IdsLinkedList.LongSpan GetLongs(int entityID) => _source._basket.GetLongSpanFor(_source._world, entityID); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Del(int entityID, int otherEntityID) => _source.DelRelation(entityID, otherEntityID); } - public readonly struct ReverseOrientation + public readonly struct ReverseOrientation : IEcsEdgeOrientation { private readonly EcsEdge _source; + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal ReverseOrientation(EcsEdge source) => _source = source; + [MethodImpl(MethodImplOptions.AggressiveInlining)] public int New(int otherEntityID, int entityID) => _source.NewRelation(entityID, otherEntityID); - public void Bind(int relationEntityID, int entityID, int otherEntityID) => _source.BindRelation(relationEntityID, otherEntityID, entityID); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Bind(int arcEntityID, int entityID, int otherEntityID) => _source.BindRelation(arcEntityID, otherEntityID, entityID); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Has(int otherEntityID, int entityID) => _source.HasRelation(entityID, otherEntityID); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public int Get(int otherEntityID, int entityID) => _source.GetRelation(entityID, otherEntityID); - public bool TryGet(int otherEntityID, int entityID, out int relationEntityID) => _source.TryGetRelation(entityID, otherEntityID, out relationEntityID); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGet(int otherEntityID, int entityID, out int arcEntityID) => _source.TryGetRelation(entityID, otherEntityID, out arcEntityID); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public IdsLinkedList.Span Get(int otherEntityID) => _source._otherBasket.GetSpanFor(otherEntityID); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public IdsLinkedList.LongSpan GetLongs(int otherEntityID) => _source._otherBasket.GetLongSpanFor(_source._otherWorld, otherEntityID); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Del(int otherEntityID, int entityID) => _source.DelRelation(entityID, otherEntityID); } @@ -209,4 +227,15 @@ namespace DCFApixels.DragonECS //} #endregion } -} + public interface IEcsEdgeOrientation + { + public int New(int entityID, int otherEntityID); + public void Bind(int arcEntityID, int entityID, int otherEntityID); + public bool Has(int entityID, int otherEntityID); + public int Get(int entityID, int otherEntityID); + public bool TryGet(int otherEntityID, int entityID, out int arcEntityID); + public IdsLinkedList.Span Get(int entityID); + public IdsLinkedList.LongSpan GetLongs(int entityID); + public void Del(int entityID, int otherEntityID); + } +} \ No newline at end of file diff --git a/src/Common/IdsBasket.cs b/src/Utils/IdsBasket.cs similarity index 100% rename from src/Common/IdsBasket.cs rename to src/Utils/IdsBasket.cs diff --git a/src/Common/IdsBasket.cs.meta b/src/Utils/IdsBasket.cs.meta similarity index 100% rename from src/Common/IdsBasket.cs.meta rename to src/Utils/IdsBasket.cs.meta diff --git a/src/Utils/RelationTargets.cs b/src/Utils/RelationTargets.cs new file mode 100644 index 0000000..2e97f79 --- /dev/null +++ b/src/Utils/RelationTargets.cs @@ -0,0 +1,83 @@ +#pragma warning disable IDE1006 // Стили именования +using DCFApixels.DragonECS.Utils; +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace DCFApixels.DragonECS +{ + [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 8)] + [Serializable] + public readonly struct RelationTargets : IEquatable + { + public static readonly RelationTargets Empty = new RelationTargets(); + + public readonly int entity; + public readonly int otherEntity; + + #region Properties + public int left + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => IsInverted ? otherEntity : entity; + } + public int right + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => IsInverted ? entity : otherEntity; + } + + public bool IsInverted + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => entity > otherEntity; // направление всегда с меньшего к большему + } + public bool IsEmpty + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => entity == 0 && otherEntity == 0; + } + + public RelationTargets Inverted + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => new RelationTargets(otherEntity, entity); + } + #endregion + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal RelationTargets(int entity, int otherEntity) + { + this.entity = entity; + this.otherEntity = otherEntity; + } + + #region operators + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RelationTargets operator -(RelationTargets a) => a.Inverted; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(RelationTargets a, RelationTargets b) => a.entity == b.entity && a.otherEntity == b.otherEntity; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(RelationTargets a, RelationTargets b) => a.entity != b.entity || a.otherEntity != b.otherEntity;s + #endregion + + #region Other + public override bool Equals(object obj) + { + return obj is RelationTargets targets && + entity == targets.entity && + otherEntity == targets.otherEntity; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(RelationTargets other) => this == other; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetHashCode() => ~entity ^ otherEntity; + public override string ToString() + { + return IsInverted ? + $"rel({entity} <- {otherEntity})" : + $"rel({entity} -> {otherEntity})"; + } + #endregion + } +} \ No newline at end of file diff --git a/src/Common/RelationTargets.cs.meta b/src/Utils/RelationTargets.cs.meta similarity index 100% rename from src/Common/RelationTargets.cs.meta rename to src/Utils/RelationTargets.cs.meta diff --git a/src/WorldGraph.cs b/src/WorldGraph.cs index 72d6476..2512539 100644 --- a/src/WorldGraph.cs +++ b/src/WorldGraph.cs @@ -1,11 +1,13 @@ -using DCFApixels.DragonECS.Relations.Utils; +using DCFApixels.DragonECS.Relations.Internal; +using DCFApixels.DragonECS.Relations.Utils; +using Leopotam.EcsLite; using System; -namespace DCFApixels.DragonECS +namespace DCFApixels.DragonECS.Relations.Internal { internal static class WorldGraph { - private static SparseArray64 _matrix = new SparseArray64(4); + private static readonly SparseArray64 _matrix = new SparseArray64(4); internal static EcsEdge Register(EcsWorld world, EcsWorld otherWorld, EcsEdgeWorld edgeWorld) { @@ -40,22 +42,25 @@ namespace DCFApixels.DragonECS internal static bool HasEdge(EcsWorld world, EcsWorld otherWorld) => HasEdge(world.id, otherWorld.id); internal static bool HasEdge(int worldID, int otherWorldID) => _matrix.Contains(worldID, otherWorldID); } +} +namespace DCFApixels.DragonECS +{ public static class WorldGraphExtensions { - public static void SetEdgeWithSelf(this EcsWorld self) => SetEdgeWith(self, self); - public static void SetEdgeWith(this EcsWorld self, EcsWorld otherWorld) + public static EcsEdge SetEdgeWithSelf(this EcsWorld self) => SetEdgeWith(self, self); + public static EcsEdge SetEdgeWith(this EcsWorld self, EcsWorld otherWorld) { if (self == null || otherWorld == null) throw new ArgumentNullException(); - WorldGraph.Register(self, otherWorld, new EcsEdgeWorld()); + return WorldGraph.Register(self, otherWorld, new EcsEdgeWorld()); } - public static void SetEdgeWithSelf(this EcsWorld self, EcsEdgeWorld relationWorld) => SetEdgeWith(self, self, relationWorld); - public static void SetEdgeWith(this EcsWorld self, EcsWorld otherWorld, EcsEdgeWorld edgeWorld) + public static EcsEdge SetEdgeWithSelf(this EcsWorld self, EcsEdgeWorld edgeWorld) => SetEdgeWith(self, self, edgeWorld); + public static EcsEdge SetEdgeWith(this EcsWorld self, EcsWorld otherWorld, EcsEdgeWorld edgeWorld) { if (self == null || otherWorld == null || edgeWorld == null) throw new ArgumentNullException(); - WorldGraph.Register(self, otherWorld, edgeWorld); + return WorldGraph.Register(self, otherWorld, edgeWorld); } public static void HasEdgeWithSelf(this EcsWorld self) => HasEdgeWith(self, self); @@ -74,11 +79,12 @@ namespace DCFApixels.DragonECS return WorldGraph.Get(self, otherWorld); } - public static void DelEdgeWithSelf(this EcsWorld self) => DelEdgeWith(self, self); - public static void DelEdgeWith(this EcsWorld self, EcsWorld otherWorld) + public static void DestroyEdgeWithSelf(this EcsWorld self) => DestroyEdgeWith(self, self); + public static void DestroyEdgeWith(this EcsWorld self, EcsWorld otherWorld) { if (self == null || otherWorld == null) throw new ArgumentNullException(); + WorldGraph.Get(self, otherWorld).EdgeWorld.Destroy(); WorldGraph.Unregister(self, otherWorld); } }