DragonECS-Graphs/src/RelationManager.cs

182 lines
7.1 KiB
C#
Raw Normal View History

2023-06-19 01:36:36 +08:00
using DCFApixels.DragonECS;
using DCFApixels.DragonECS.Relations.Utils;
2023-06-22 03:54:20 +08:00
using System.Collections;
using System.Runtime.CompilerServices;
2023-06-19 01:36:36 +08:00
namespace DragonECS.DragonECS
{
2023-06-22 03:54:20 +08:00
//Relation entity
//Relation
//Relation component
public readonly struct Relations
2023-06-19 01:36:36 +08:00
{
2023-06-22 03:54:20 +08:00
public readonly RelationManager manager;
public Relations(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-22 03:54:20 +08:00
private SparseArray64<int> _relationsMatrix = new SparseArray64<int>();
public readonly Orientation Forward;
public readonly Orientation 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
IdsBasket basket = new IdsBasket(256);
IdsBasket otherBasket = new IdsBasket(256);
2023-06-22 03:55:30 +08:00
Forward = new Orientation(this, relationWorld, basket, otherBasket);
Reverse = new Orientation(this, relationWorld, otherBasket, basket);
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-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-22 03:54:20 +08:00
#region Orientation
public readonly struct Orientation
{
private readonly RelationManager _source;
private readonly EcsWorld _relationWorld;
private readonly IdsBasket _basket;
private readonly IdsBasket _otherBasket;
2023-06-22 03:55:30 +08:00
public Orientation(RelationManager source, EcsWorld relationWorld, IdsBasket basket, IdsBasket otherBasket)
2023-06-22 03:54:20 +08:00
{
_source = source;
_relationWorld = relationWorld;
_basket = basket;
_otherBasket = otherBasket;
}
#region New/Del
public 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);
_source._relationTargets[e] = new RelationTargets(entityID, otherEntityID);
return e;
}
public void DelRelation(int entityID, int otherEntityID)
{
if (!_source._relationsMatrix.TryGetValue(entityID, otherEntityID, out int e))
throw new EcsRelationException();
_basket.DelHead(entityID);
_otherBasket.Del(entityID);
_relationWorld.DelEntity(e);
_source._relationTargets[e] = RelationTargets.Empty;
}
#endregion
#region Has
public bool HasRelation(int entityID, int otherEntityID) => _source._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
public int GetRelation(int entityID, int otherEntityID)
{
if (!_source._relationsMatrix.TryGetValue(entityID, otherEntityID, out int e))
throw new EcsRelationException();
return e;
}
public bool TryGetRelation(int entityID, int otherEntityID, out int entity)
{
return _source._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
//ReadOnlySpan<int> временная заглушка, потому тут будет спан из линкедлиста
public ReadOnlySpan<int> GetRelations(int entityID)
{
throw new NotImplementedException();
}
//ReadOnlySpan<int> временная заглушка, потому тут будет спан из линкедлиста
public ReadOnlySpan<int> GetRelationsWith(EcsSubject subject, int entityID)
{
if (subject.World != _relationWorld)
throw new ArgumentException();
throw new NotImplementedException();
}
#endregion
2023-06-19 01:36:36 +08:00
}
2023-06-22 03:54:20 +08:00
#endregion
2023-06-19 01:36:36 +08:00
}
public static class WorldRelationExtensions
{
public static void SetRelationWith(this EcsWorld self, EcsWorld otherWorld)
{
WorldRelationsMatrix.Register(self, otherWorld, new EcsRelationWorld());
}
public static void SetRelationWith(this EcsWorld self, EcsWorld otherWorld, EcsRelationWorld relationWorld)
{
WorldRelationsMatrix.Register(self, otherWorld, relationWorld);
}
public static void DelRelationWith(this EcsWorld self, EcsWorld otherWorld)
{
WorldRelationsMatrix.Unregister(self, otherWorld);
}
}
}