2023-06-22 11:01:43 +08:00
|
|
|
|
using DCFApixels.DragonECS.Relations.Utils;
|
|
|
|
|
using System;
|
2023-06-22 03:54:20 +08:00
|
|
|
|
using System.Runtime.CompilerServices;
|
2023-06-19 01:36:36 +08:00
|
|
|
|
|
2023-06-22 11:01:43 +08:00
|
|
|
|
namespace DCFApixels.DragonECS
|
2023-06-19 01:36:36 +08:00
|
|
|
|
{
|
2023-06-22 03:54:20 +08:00
|
|
|
|
//Relation entity
|
|
|
|
|
//Relation
|
|
|
|
|
//Relation component
|
2023-06-22 11:01:43 +08:00
|
|
|
|
public readonly struct RelationData
|
2023-06-19 01:36:36 +08:00
|
|
|
|
{
|
2023-06-22 03:54:20 +08:00
|
|
|
|
public readonly RelationManager manager;
|
2023-06-22 11:01:43 +08:00
|
|
|
|
public RelationData(RelationManager manager)
|
2023-06-19 01:36:36 +08:00
|
|
|
|
{
|
2023-06-22 03:54:20 +08:00
|
|
|
|
this.manager = manager;
|
2023-06-19 01:36:36 +08:00
|
|
|
|
}
|
2023-06-22 03:54:20 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
public ref readonly RelationTargets GetRelationTargets(int relationEntityID) => ref manager.GetRelationTargets(relationEntityID);
|
2023-06-19 01:36:36 +08:00
|
|
|
|
}
|
2023-06-22 03:54:20 +08:00
|
|
|
|
public class RelationManager : IEcsWorldEventListener, IEcsEntityEventListener
|
2023-06-19 01:36:36 +08:00
|
|
|
|
{
|
|
|
|
|
private EcsRelationWorld _relationWorld;
|
|
|
|
|
|
|
|
|
|
private EcsWorld _world;
|
|
|
|
|
private EcsWorld _otherWorld;
|
|
|
|
|
|
2023-06-23 01:49:13 +08:00
|
|
|
|
private readonly IdsBasket _basket = new IdsBasket(256);
|
|
|
|
|
private readonly IdsBasket _otherBasket = new IdsBasket(256);
|
2023-06-22 03:54:20 +08:00
|
|
|
|
private SparseArray64<int> _relationsMatrix = new SparseArray64<int>();
|
|
|
|
|
|
2023-06-23 01:49:13 +08:00
|
|
|
|
public readonly ForwardOrientation Forward;
|
|
|
|
|
public readonly ReverseOrientation Reverse;
|
2023-06-19 01:36:36 +08:00
|
|
|
|
|
2023-06-22 03:54:20 +08:00
|
|
|
|
private RelationTargets[] _relationTargets;
|
|
|
|
|
|
|
|
|
|
public EcsWorld World => _world;
|
2023-06-19 01:36:36 +08:00
|
|
|
|
public EcsWorld RelationWorld => _relationWorld;
|
2023-06-22 03:54:20 +08:00
|
|
|
|
public EcsWorld OtherWorld => _otherWorld;
|
2023-06-19 01:36:36 +08:00
|
|
|
|
public bool IsSolo => _world == _otherWorld;
|
|
|
|
|
|
2023-06-22 03:54:20 +08:00
|
|
|
|
internal RelationManager(EcsWorld world, EcsRelationWorld relationWorld, EcsWorld otherWorld)
|
2023-06-19 01:36:36 +08:00
|
|
|
|
{
|
|
|
|
|
_relationWorld = relationWorld;
|
|
|
|
|
_world = world;
|
|
|
|
|
_otherWorld = otherWorld;
|
|
|
|
|
|
2023-06-22 03:54:20 +08:00
|
|
|
|
_relationTargets = new RelationTargets[relationWorld.Capacity];
|
|
|
|
|
|
2023-06-19 01:36:36 +08:00
|
|
|
|
_relationWorld.AddListener(worldEventListener: this);
|
|
|
|
|
_relationWorld.AddListener(entityEventListener: this);
|
2023-06-22 03:54:20 +08:00
|
|
|
|
|
2023-06-23 01:49:13 +08:00
|
|
|
|
Forward = new ForwardOrientation(this);
|
|
|
|
|
Reverse = new ReverseOrientation(this);
|
2023-06-19 01:36:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-06-22 03:54:20 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
public ref readonly RelationTargets GetRelationTargets(int relationEntityID)
|
2023-06-19 01:36:36 +08:00
|
|
|
|
{
|
2023-06-22 03:54:20 +08:00
|
|
|
|
return ref _relationTargets[relationEntityID];
|
2023-06-19 01:36:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-06-23 01:49:13 +08:00
|
|
|
|
#region Methods
|
|
|
|
|
|
|
|
|
|
#region New/Del
|
|
|
|
|
private int NewRelation(int entityID, int otherEntityID)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
if (HasRelation(entityID, otherEntityID))
|
|
|
|
|
throw new EcsRelationException();
|
|
|
|
|
int e = _relationWorld.NewEmptyEntity();
|
|
|
|
|
_basket.AddToHead(entityID, otherEntityID);
|
|
|
|
|
_otherBasket.AddToHead(otherEntityID, entityID);
|
|
|
|
|
_relationsMatrix.Add(entityID, otherEntityID, e);
|
|
|
|
|
_relationTargets[e] = new RelationTargets(entityID, otherEntityID);
|
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
private void DelRelation(int entityID, int otherEntityID)
|
|
|
|
|
{
|
|
|
|
|
if (!_relationsMatrix.TryGetValue(entityID, otherEntityID, out int e))
|
|
|
|
|
throw new EcsRelationException();
|
|
|
|
|
_relationsMatrix.Remove(entityID, otherEntityID);
|
|
|
|
|
_basket.DelHead(entityID);
|
|
|
|
|
_otherBasket.Del(entityID);
|
|
|
|
|
_relationWorld.DelEntity(e);
|
|
|
|
|
_relationTargets[e] = RelationTargets.Empty;
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Has
|
|
|
|
|
private bool HasRelation(int entityID, int otherEntityID) => _relationsMatrix.Contains(entityID, otherEntityID);
|
|
|
|
|
//public bool HasRelationWith(EcsSubject subject, int entityID, int otherEntityID)
|
|
|
|
|
//{
|
|
|
|
|
// if (subject.World != _relationWorld)
|
|
|
|
|
// throw new ArgumentException();
|
|
|
|
|
// return _source._relationsMatrix.TryGetValue(entityID, otherEntityID, out int entity) && subject.IsMatches(entity);
|
|
|
|
|
//}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region GetRelation
|
|
|
|
|
private int GetRelation(int entityID, int otherEntityID)
|
|
|
|
|
{
|
|
|
|
|
if (!_relationsMatrix.TryGetValue(entityID, otherEntityID, out int e))
|
|
|
|
|
throw new EcsRelationException();
|
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
private bool TryGetRelation(int entityID, int otherEntityID, out int entity)
|
|
|
|
|
{
|
|
|
|
|
return _relationsMatrix.TryGetValue(entityID, otherEntityID, out entity);
|
|
|
|
|
}
|
|
|
|
|
//public bool TryGetRelation(EcsSubject subject, int entityID, int otherEntityID, out int entity)
|
|
|
|
|
//{
|
|
|
|
|
// return _source._relationsMatrix.TryGetValue(entityID, otherEntityID, out entity) && subject.IsMatches(entity);
|
|
|
|
|
//}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
//#region GetRelations
|
|
|
|
|
//private IdsLinkedList.Span GetRelations(int entityID)
|
|
|
|
|
//{
|
|
|
|
|
// return _basket.GetSpanFor(entityID);
|
|
|
|
|
//}
|
|
|
|
|
////ReadOnlySpan<int> временная заглушка, потому тут будет спан из линкедлиста
|
|
|
|
|
////public ReadOnlySpan<int> GetRelationsWith(EcsSubject subject, int entityID)
|
|
|
|
|
////{
|
|
|
|
|
//// if (subject.World != _relationWorld)
|
|
|
|
|
//// throw new ArgumentException();
|
|
|
|
|
//// throw new NotImplementedException();
|
|
|
|
|
////}
|
|
|
|
|
//#endregion
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
2023-06-22 03:54:20 +08:00
|
|
|
|
#region Callbacks
|
|
|
|
|
void IEcsWorldEventListener.OnWorldResize(int newSize)
|
|
|
|
|
{
|
|
|
|
|
Array.Resize(ref _relationTargets, newSize);
|
|
|
|
|
}
|
2023-06-19 01:36:36 +08:00
|
|
|
|
void IEcsWorldEventListener.OnReleaseDelEntityBuffer(ReadOnlySpan<int> buffer) { }
|
|
|
|
|
void IEcsWorldEventListener.OnWorldDestroy() { }
|
|
|
|
|
|
|
|
|
|
void IEcsEntityEventListener.OnNewEntity(int entityID) { }
|
|
|
|
|
void IEcsEntityEventListener.OnDelEntity(int entityID)
|
|
|
|
|
{
|
2023-06-22 03:54:20 +08:00
|
|
|
|
ref RelationTargets rel = ref _relationTargets[entityID];
|
|
|
|
|
if (_relationsMatrix.Contains(rel.entity, rel.otherEntity))
|
|
|
|
|
Forward.DelRelation(rel.entity, rel.otherEntity);
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
2023-06-19 01:36:36 +08:00
|
|
|
|
|
2023-06-23 01:49:13 +08:00
|
|
|
|
|
2023-06-22 03:54:20 +08:00
|
|
|
|
#region Orientation
|
2023-06-23 01:49:13 +08:00
|
|
|
|
public readonly struct ForwardOrientation
|
2023-06-22 03:54:20 +08:00
|
|
|
|
{
|
|
|
|
|
private readonly RelationManager _source;
|
2023-06-23 01:49:13 +08:00
|
|
|
|
internal ForwardOrientation(RelationManager source) => _source = source;
|
|
|
|
|
public int NewRelation(int entityID, int otherEntityID) => _source.NewRelation(entityID, otherEntityID);
|
|
|
|
|
public void DelRelation(int entityID, int otherEntityID) => _source.DelRelation(entityID, otherEntityID);
|
|
|
|
|
public bool HasRelation(int entityID, int otherEntityID) => _source.HasRelation(entityID, otherEntityID);
|
|
|
|
|
public int GetRelation(int entityID, int otherEntityID) => _source.GetRelation(entityID, otherEntityID);
|
|
|
|
|
public bool TryGetRelation(int entityID, int otherEntityID, out int relationEntityID) => _source.TryGetRelation(entityID, otherEntityID, out relationEntityID);
|
2023-06-23 01:52:51 +08:00
|
|
|
|
public IdsLinkedList.Span GetRelations(int entityID) => _source._basket.GetSpanFor(entityID);
|
2023-06-23 01:49:13 +08:00
|
|
|
|
}
|
|
|
|
|
public readonly struct ReverseOrientation
|
|
|
|
|
{
|
|
|
|
|
private readonly RelationManager _source;
|
|
|
|
|
internal ReverseOrientation(RelationManager source) => _source = source;
|
|
|
|
|
public int NewRelation(int otherEntityID, int entityID) => _source.NewRelation(entityID, otherEntityID);
|
|
|
|
|
public void DelRelation(int otherEntityID, int entityID) => _source.DelRelation(entityID, otherEntityID);
|
|
|
|
|
public bool HasRelation(int otherEntityID, int entityID) => _source.HasRelation(entityID, otherEntityID);
|
|
|
|
|
public int GetRelation(int otherEntityID, int entityID) => _source.GetRelation(entityID, otherEntityID);
|
|
|
|
|
public bool TryGetRelation(int otherEntityID, int entityID, out int relationEntityID) => _source.TryGetRelation(entityID, otherEntityID, out relationEntityID);
|
2023-06-23 01:52:51 +08:00
|
|
|
|
public IdsLinkedList.Span GetRelations(int otherEntityID) => _source._otherBasket.GetSpanFor(otherEntityID);
|
2023-06-19 01:36:36 +08:00
|
|
|
|
}
|
2023-06-22 09:10:51 +08:00
|
|
|
|
|
|
|
|
|
public struct RelationsSpan
|
|
|
|
|
{
|
|
|
|
|
private readonly IdsBasket _basket;
|
2023-06-22 14:30:10 +08:00
|
|
|
|
private readonly EcsAspect _aspect;
|
2023-06-22 09:10:51 +08:00
|
|
|
|
}
|
2023-06-22 03:54:20 +08:00
|
|
|
|
#endregion
|
2023-06-19 01:36:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static class WorldRelationExtensions
|
|
|
|
|
{
|
2023-06-22 11:01:43 +08:00
|
|
|
|
public static void SetRelationWithSelf(this EcsWorld self) => SetRelationWith(self, self);
|
2023-06-19 01:36:36 +08:00
|
|
|
|
public static void SetRelationWith(this EcsWorld self, EcsWorld otherWorld)
|
|
|
|
|
{
|
2023-06-22 11:01:43 +08:00
|
|
|
|
if (self == null || otherWorld == null)
|
|
|
|
|
throw new ArgumentNullException();
|
2023-06-19 01:36:36 +08:00
|
|
|
|
WorldRelationsMatrix.Register(self, otherWorld, new EcsRelationWorld());
|
|
|
|
|
}
|
2023-06-22 11:01:43 +08:00
|
|
|
|
public static void SetRelationWithSelf(this EcsWorld self, EcsRelationWorld relationWorld) => SetRelationWith(self, relationWorld);
|
2023-06-19 01:36:36 +08:00
|
|
|
|
public static void SetRelationWith(this EcsWorld self, EcsWorld otherWorld, EcsRelationWorld relationWorld)
|
|
|
|
|
{
|
2023-06-22 11:01:43 +08:00
|
|
|
|
if (self == null || otherWorld == null || relationWorld == null)
|
|
|
|
|
throw new ArgumentNullException();
|
2023-06-19 01:36:36 +08:00
|
|
|
|
WorldRelationsMatrix.Register(self, otherWorld, relationWorld);
|
|
|
|
|
}
|
2023-06-22 11:01:43 +08:00
|
|
|
|
|
|
|
|
|
public static void DelRelationWithSelf(this EcsWorld self, EcsWorld otherWorld) => DelRelationWith(self, self);
|
2023-06-19 01:36:36 +08:00
|
|
|
|
public static void DelRelationWith(this EcsWorld self, EcsWorld otherWorld)
|
|
|
|
|
{
|
2023-06-22 11:01:43 +08:00
|
|
|
|
if (self == null || otherWorld == null)
|
|
|
|
|
throw new ArgumentNullException();
|
2023-06-19 01:36:36 +08:00
|
|
|
|
WorldRelationsMatrix.Unregister(self, otherWorld);
|
|
|
|
|
}
|
2023-06-22 11:01:43 +08:00
|
|
|
|
|
|
|
|
|
public static RelationManager GetRelationWithSelf(this EcsWorld self) => GetRelationWith(self, self);
|
|
|
|
|
public static RelationManager GetRelationWith(this EcsWorld self, EcsWorld otherWorld)
|
|
|
|
|
{
|
|
|
|
|
if (self == null || otherWorld == null)
|
|
|
|
|
throw new ArgumentNullException();
|
|
|
|
|
return WorldRelationsMatrix.Get(self, otherWorld);
|
|
|
|
|
}
|
2023-06-19 01:36:36 +08:00
|
|
|
|
}
|
|
|
|
|
}
|