This commit is contained in:
Mikhail 2023-12-12 00:14:28 +08:00
parent 86840b6637
commit 5118e5887d
12 changed files with 158 additions and 55 deletions

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 88f41ce69c4d95c47aefc4360c26874f guid: 38d25d74b63bca04484cf081895872f0
folderAsset: yes folderAsset: yes
DefaultImporter: DefaultImporter:
externalObjects: {} externalObjects: {}

View File

@ -0,0 +1,4 @@
namespace DCFApixels.DragonECS
{
public struct ChildOf : IEcsTagComponent { }
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1de8d8a49b0d49640847d1cec330fc4b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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;
}
}

View File

@ -26,15 +26,15 @@ namespace DCFApixels.DragonECS
public EcsWorld OtherWorld => _otherWorld; public EcsWorld OtherWorld => _otherWorld;
public EcsEdgeWorld EdgeWorld => _edgeWorld; 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; _world = world;
_otherWorld = otherWorld; _otherWorld = otherWorld;
_relationTargets = new RelationTargets[relationWorld.Capacity]; _relationTargets = new RelationTargets[edgeWorld.Capacity];
_edgeWorld.AddListener(worldEventListener: this); _edgeWorld.AddListener(worldEventListener: this);
_edgeWorld.AddListener(entityEventListener: this); _edgeWorld.AddListener(entityEventListener: this);
@ -44,9 +44,9 @@ namespace DCFApixels.DragonECS
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [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 #region Methods
@ -149,30 +149,48 @@ namespace DCFApixels.DragonECS
#endregion #endregion
#region Orientation #region Orientation
public readonly struct ForwardOrientation public readonly struct ForwardOrientation : IEcsEdgeOrientation
{ {
private readonly EcsEdge _source; private readonly EcsEdge _source;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal ForwardOrientation(EcsEdge source) => _source = source; internal ForwardOrientation(EcsEdge source) => _source = source;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int New(int entityID, int otherEntityID) => _source.NewRelation(entityID, otherEntityID); 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); 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 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); 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); 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 void Del(int entityID, int otherEntityID) => _source.DelRelation(entityID, otherEntityID);
} }
public readonly struct ReverseOrientation public readonly struct ReverseOrientation : IEcsEdgeOrientation
{ {
private readonly EcsEdge _source; private readonly EcsEdge _source;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal ReverseOrientation(EcsEdge source) => _source = source; internal ReverseOrientation(EcsEdge source) => _source = source;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int New(int otherEntityID, int entityID) => _source.NewRelation(entityID, otherEntityID); 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); 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 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); 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); 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); public void Del(int otherEntityID, int entityID) => _source.DelRelation(entityID, otherEntityID);
} }
@ -209,4 +227,15 @@ namespace DCFApixels.DragonECS
//} //}
#endregion #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);
}
}

View File

@ -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<RelationTargets>
{
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
}
}

View File

@ -1,11 +1,13 @@
using DCFApixels.DragonECS.Relations.Utils; using DCFApixels.DragonECS.Relations.Internal;
using DCFApixels.DragonECS.Relations.Utils;
using Leopotam.EcsLite;
using System; using System;
namespace DCFApixels.DragonECS namespace DCFApixels.DragonECS.Relations.Internal
{ {
internal static class WorldGraph internal static class WorldGraph
{ {
private static SparseArray64<EcsEdge> _matrix = new SparseArray64<EcsEdge>(4); private static readonly SparseArray64<EcsEdge> _matrix = new SparseArray64<EcsEdge>(4);
internal static EcsEdge Register(EcsWorld world, EcsWorld otherWorld, EcsEdgeWorld edgeWorld) 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(EcsWorld world, EcsWorld otherWorld) => HasEdge(world.id, otherWorld.id);
internal static bool HasEdge(int worldID, int otherWorldID) => _matrix.Contains(worldID, otherWorldID); internal static bool HasEdge(int worldID, int otherWorldID) => _matrix.Contains(worldID, otherWorldID);
} }
}
namespace DCFApixels.DragonECS
{
public static class WorldGraphExtensions public static class WorldGraphExtensions
{ {
public static void SetEdgeWithSelf(this EcsWorld self) => SetEdgeWith(self, self); public static EcsEdge SetEdgeWithSelf(this EcsWorld self) => SetEdgeWith(self, self);
public static void SetEdgeWith(this EcsWorld self, EcsWorld otherWorld) public static EcsEdge SetEdgeWith(this EcsWorld self, EcsWorld otherWorld)
{ {
if (self == null || otherWorld == null) if (self == null || otherWorld == null)
throw new ArgumentNullException(); 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 EcsEdge SetEdgeWithSelf(this EcsWorld self, EcsEdgeWorld edgeWorld) => SetEdgeWith(self, self, edgeWorld);
public static void SetEdgeWith(this EcsWorld self, EcsWorld otherWorld, EcsEdgeWorld edgeWorld) public static EcsEdge SetEdgeWith(this EcsWorld self, EcsWorld otherWorld, EcsEdgeWorld edgeWorld)
{ {
if (self == null || otherWorld == null || edgeWorld == null) if (self == null || otherWorld == null || edgeWorld == null)
throw new ArgumentNullException(); throw new ArgumentNullException();
WorldGraph.Register(self, otherWorld, edgeWorld); return WorldGraph.Register(self, otherWorld, edgeWorld);
} }
public static void HasEdgeWithSelf(this EcsWorld self) => HasEdgeWith(self, self); public static void HasEdgeWithSelf(this EcsWorld self) => HasEdgeWith(self, self);
@ -74,11 +79,12 @@ namespace DCFApixels.DragonECS
return WorldGraph.Get(self, otherWorld); return WorldGraph.Get(self, otherWorld);
} }
public static void DelEdgeWithSelf(this EcsWorld self) => DelEdgeWith(self, self); public static void DestroyEdgeWithSelf(this EcsWorld self) => DestroyEdgeWith(self, self);
public static void DelEdgeWith(this EcsWorld self, EcsWorld otherWorld) public static void DestroyEdgeWith(this EcsWorld self, EcsWorld otherWorld)
{ {
if (self == null || otherWorld == null) if (self == null || otherWorld == null)
throw new ArgumentNullException(); throw new ArgumentNullException();
WorldGraph.Get(self, otherWorld).EdgeWorld.Destroy();
WorldGraph.Unregister(self, otherWorld); WorldGraph.Unregister(self, otherWorld);
} }
} }