ReworkWorld

This commit is contained in:
Mikhail 2023-03-02 14:42:44 +08:00
parent d64d4407c9
commit b73652cb37
19 changed files with 473 additions and 1866 deletions

View File

@ -6,196 +6,37 @@ namespace DCFApixels.DragonECS
#region Incs/Excs base
public interface ICondition
{
public int[] GetComponentsIDs();
public int[] GetComponentsIDs<TWorldArchetype>() where TWorldArchetype : IWorldArchetype;
}
#endregion
#region Incs
public interface IInc : ICondition { }
public struct Inc : IInc
{
public int[] GetComponentsIDs<TWorldArchetype>() where TWorldArchetype : IWorldArchetype => Array.Empty<int>();
}
public struct Inc<T0> : IInc
{
public int[] GetComponentsIDs()
public int[] GetComponentsIDs<TWorldArchetype>()
where TWorldArchetype : IWorldArchetype
{
return new int[]
{
ComponentType<T0>.globalID
EcsWorld<TWorldArchetype>.ComponentType<T0>.uniqueID
};
}
}
public struct Inc<T0, T1> : IInc
{
public int[] GetComponentsIDs()
public int[] GetComponentsIDs<TWorldArchetype>()
where TWorldArchetype : IWorldArchetype
{
return new int[]
{
ComponentType<T0>.globalID,
ComponentType<T1>.globalID
};
}
}
public struct Inc<T0, T1, T2> : IInc
{
public int[] GetComponentsIDs()
{
return new int[]
{
ComponentType<T0>.globalID,
ComponentType<T1>.globalID,
ComponentType<T2>.globalID
};
}
}
public struct Inc<T0, T1, T2, T3> : IInc
{
public int[] GetComponentsIDs()
{
return new int[]
{
ComponentType<T0>.globalID,
ComponentType<T1>.globalID,
ComponentType<T2>.globalID,
ComponentType<T3>.globalID
};
}
}
public struct Inc<T0, T1, T2, T3, T4> : IInc
{
public int[] GetComponentsIDs()
{
return new int[]
{
ComponentType<T0>.globalID,
ComponentType<T1>.globalID,
ComponentType<T2>.globalID,
ComponentType<T3>.globalID,
ComponentType<T4>.globalID
};
}
}
public struct Inc<T0, T1, T2, T3, T4, T5> : IInc
{
public int[] GetComponentsIDs()
{
return new int[]
{
ComponentType<T0>.globalID,
ComponentType<T1>.globalID,
ComponentType<T2>.globalID,
ComponentType<T3>.globalID,
ComponentType<T4>.globalID,
ComponentType<T5>.globalID
};
}
}
public struct Inc<T0, T1, T2, T3, T4, T5, T6> : IInc
{
public int[] GetComponentsIDs()
{
return new int[]
{
ComponentType<T0>.globalID,
ComponentType<T1>.globalID,
ComponentType<T2>.globalID,
ComponentType<T3>.globalID,
ComponentType<T4>.globalID,
ComponentType<T5>.globalID,
ComponentType<T6>.globalID
};
}
}
public struct Inc<T0, T1, T2, T3, T4, T5, T6, T7> : IInc
{
public int[] GetComponentsIDs()
{
return new int[]
{
ComponentType<T0>.globalID,
ComponentType<T1>.globalID,
ComponentType<T2>.globalID,
ComponentType<T3>.globalID,
ComponentType<T4>.globalID,
ComponentType<T5>.globalID,
ComponentType<T6>.globalID,
ComponentType<T7>.globalID
};
}
}
public struct Inc<T0, T1, T2, T3, T4, T5, T6, T7, T8> : IInc
{
public int[] GetComponentsIDs()
{
return new int[]
{
ComponentType<T0>.globalID,
ComponentType<T1>.globalID,
ComponentType<T2>.globalID,
ComponentType<T3>.globalID,
ComponentType<T4>.globalID,
ComponentType<T5>.globalID,
ComponentType<T6>.globalID,
ComponentType<T7>.globalID,
ComponentType<T8>.globalID
};
}
}
public struct Inc<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> : IInc
{
public int[] GetComponentsIDs()
{
return new int[]
{
ComponentType<T0>.globalID,
ComponentType<T1>.globalID,
ComponentType<T2>.globalID,
ComponentType<T3>.globalID,
ComponentType<T4>.globalID,
ComponentType<T5>.globalID,
ComponentType<T6>.globalID,
ComponentType<T7>.globalID,
ComponentType<T8>.globalID,
ComponentType<T9>.globalID
};
}
}
public struct Inc<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> : IInc
{
public int[] GetComponentsIDs()
{
return new int[]
{
ComponentType<T0>.globalID,
ComponentType<T1>.globalID,
ComponentType<T2>.globalID,
ComponentType<T3>.globalID,
ComponentType<T4>.globalID,
ComponentType<T5>.globalID,
ComponentType<T6>.globalID,
ComponentType<T7>.globalID,
ComponentType<T8>.globalID,
ComponentType<T9>.globalID,
ComponentType<T10>.globalID
};
}
}
public struct Inc<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> : IInc
{
public int[] GetComponentsIDs()
{
return new int[]
{
ComponentType<T0>.globalID,
ComponentType<T1>.globalID,
ComponentType<T2>.globalID,
ComponentType<T3>.globalID,
ComponentType<T4>.globalID,
ComponentType<T5>.globalID,
ComponentType<T6>.globalID,
ComponentType<T7>.globalID,
ComponentType<T8>.globalID,
ComponentType<T9>.globalID,
ComponentType<T10>.globalID,
ComponentType<T11>.globalID
EcsWorld<TWorldArchetype>.ComponentType<T0>.uniqueID,
EcsWorld<TWorldArchetype>.ComponentType<T1>.uniqueID
};
}
}
@ -204,112 +45,114 @@ namespace DCFApixels.DragonECS
#region Excs
public interface IExc : ICondition { }
public struct Exc : IExc
{
public int[] GetComponentsIDs<TWorldArchetype>() where TWorldArchetype : IWorldArchetype => Array.Empty<int>();
}
public struct Exc<T0> : IExc
{
public int[] GetComponentsIDs()
public int[] GetComponentsIDs<TWorldArchetype>()
where TWorldArchetype : IWorldArchetype
{
return new int[]
{
ComponentType<T0>.globalID
EcsWorld<TWorldArchetype>.ComponentType<T0>.uniqueID,
};
}
}
public struct Exc<T0, T1> : IExc
{
public int[] GetComponentsIDs()
public int[] GetComponentsIDs<TWorldArchetype>()
where TWorldArchetype : IWorldArchetype
{
return new int[]
{
ComponentType<T0>.globalID,
ComponentType<T1>.globalID
EcsWorld<TWorldArchetype>.ComponentType<T0>.uniqueID,
EcsWorld<TWorldArchetype>.ComponentType<T1>.uniqueID
};
}
}
public struct Exc<T0, T1, T2> : IExc
#endregion
#region BakedMask
public abstract class BakedMask
{
public int[] GetComponentsIDs()
internal readonly int[] Inc;
internal readonly int[] Exc;
internal readonly Mask Mask;
internal int IncCount
{
return new int[]
{
ComponentType<T0>.globalID,
ComponentType<T1>.globalID,
ComponentType<T2>.globalID
};
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => Inc.Length;
}
internal int ExcCount
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => Exc.Length;
}
//Уникальный айди в рамках одного архиетипа мира
internal abstract int UniqueID { get; }
internal abstract Type WorldArchetypeType { get; }
protected BakedMask(int[] inc, int[] exc, Mask mask)
{
Inc = inc;
Exc = exc;
Mask = mask;
}
}
public struct Exc<T0, T1, T2, T3> : IExc
public abstract class BakedMask<TWorldArchetype> : BakedMask
{
public int[] GetComponentsIDs()
{
return new int[]
{
ComponentType<T0>.globalID,
ComponentType<T1>.globalID,
ComponentType<T2>.globalID,
ComponentType<T3>.globalID
};
}
internal static int increment = 1;
internal static int capacity = 512;
protected BakedMask(int[] inc, int[] exc, Mask mask) : base(inc, exc, mask) { }
}
public struct Exc<T0, T1, T2, T3, T4> : IExc
public sealed class BakedMask<TWorldArchetype, TMask> : BakedMask<TWorldArchetype>
where TWorldArchetype : IWorldArchetype
where TMask : MaskSingleton<TMask>
{
public int[] GetComponentsIDs()
public static readonly int uniqueID;
static BakedMask()
{
return new int[]
{
ComponentType<T0>.globalID,
ComponentType<T1>.globalID,
ComponentType<T2>.globalID,
ComponentType<T3>.globalID,
ComponentType<T4>.globalID
};
uniqueID = increment++;
#if DEBUG || DCFAECS_NO_SANITIZE_CHECKS
if (uniqueID >= ushort.MaxValue)
throw new EcsFrameworkException($"No more room for new BakedMask for this {typeof(TWorldArchetype).FullName} IWorldArchetype");
#endif
if (increment > capacity)
capacity <<= 1;
_instance = new BakedMask<TWorldArchetype, TMask>();
}
}
public struct Exc<T0, T1, T2, T3, T4, T5> : IExc
{
public int[] GetComponentsIDs()
private BakedMask() : base(
MaskSingleton<TMask>.Instance.MakeInc<IWorldArchetype>(),
MaskSingleton<TMask>.Instance.MakeExc<IWorldArchetype>(),
MaskSingleton<TMask>.Instance)
{ }
private static readonly BakedMask<TWorldArchetype, TMask> _instance = new BakedMask<TWorldArchetype, TMask>();
public static BakedMask<TWorldArchetype, TMask> Instance
{
return new int[]
{
ComponentType<T0>.globalID,
ComponentType<T1>.globalID,
ComponentType<T2>.globalID,
ComponentType<T3>.globalID,
ComponentType<T4>.globalID,
ComponentType<T5>.globalID
};
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _instance;
}
}
public struct Exc<T0, T1, T2, T3, T4, T5, T6> : IExc
{
public int[] GetComponentsIDs()
internal override int UniqueID
{
return new int[]
{
ComponentType<T0>.globalID,
ComponentType<T1>.globalID,
ComponentType<T2>.globalID,
ComponentType<T3>.globalID,
ComponentType<T4>.globalID,
ComponentType<T5>.globalID,
ComponentType<T6>.globalID
};
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => uniqueID;
}
}
public struct Exc<T0, T1, T2, T3, T4, T5, T6, T7> : IExc
{
public int[] GetComponentsIDs()
internal override Type WorldArchetypeType
{
return new int[]
{
ComponentType<T0>.globalID,
ComponentType<T1>.globalID,
ComponentType<T2>.globalID,
ComponentType<T3>.globalID,
ComponentType<T4>.globalID,
ComponentType<T5>.globalID,
ComponentType<T6>.globalID,
ComponentType<T7>.globalID
};
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => typeof(IWorldArchetype);
}
}
#endregion
@ -317,111 +160,76 @@ namespace DCFApixels.DragonECS
#region Masks
public abstract class Mask
{
protected internal static int _typeIDIncrement = 0;
internal abstract int[] Include { get; }
internal abstract int[] Exclude { get; }
public abstract int ID { get; }
public int IncCount
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => Include.Length;
}
public int ExcCount
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => Exclude.Length;
}
internal abstract int[] MakeInc<TWorldArchetype>() where TWorldArchetype : IWorldArchetype;
internal abstract int[] MakeExc<TWorldArchetype>() where TWorldArchetype : IWorldArchetype;
public abstract BakedMask GetBaked<TWorldArchetype>() where TWorldArchetype : IWorldArchetype;
}
public sealed class Mask<TInc> : Mask
where TInc : struct, IInc
public abstract class MaskSingleton<TSelf> : Mask
where TSelf : Mask
{
internal static readonly int[] include = new TInc().GetComponentsIDs();
internal static readonly int[] exclude = Array.Empty<int>();
public static readonly int id = _typeIDIncrement++;
private static Mask<TInc> _instance = new Mask<TInc>();
private Mask() { }
public static Mask<TInc> Instance
protected static TSelf _instance;
internal static TSelf Instance
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _instance;
}
public override int ID
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => id;
}
internal override int[] Include
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => include;
}
internal override int[] Exclude
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => exclude;
}
}
public sealed class Mask<TInc, TExc> : Mask
public class Mask<TInc> : MaskSingleton<Mask<TInc>>
where TInc : struct, IInc
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int[] MakeInc<TWorldArchetype>() => new TInc().GetComponentsIDs<TWorldArchetype>();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int[] MakeExc<TWorldArchetype>() => Array.Empty<int>();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override BakedMask GetBaked<TWorldArchetype>()
{
return BakedMask<TWorldArchetype, Mask<TInc>>.Instance;
}
static Mask() { _instance = new Mask<TInc>(); }
}
public class Mask<TInc, TExc> : MaskSingleton<Mask<TInc, TExc>>
where TInc : struct, IInc
where TExc : struct, IExc
{
internal static readonly int[] include = new TInc().GetComponentsIDs();
internal static readonly int[] exclude = new TExc().GetComponentsIDs();
public static readonly int id = _typeIDIncrement++;
private static Mask<TInc, TExc> _instance = new Mask<TInc, TExc>();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int[] MakeInc<TWorldArchetype>() => new TInc().GetComponentsIDs<TWorldArchetype>();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int[] MakeExc<TWorldArchetype>() => new TExc().GetComponentsIDs<TWorldArchetype>();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override BakedMask GetBaked<TWorldArchetype>()
{
return BakedMask<TWorldArchetype, Mask<TInc, TExc>>.Instance;
}
private Mask() { }
public static Mask<TInc, TExc> Instance
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _instance;
}
public override int ID
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => id;
}
internal override int[] Include
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => include;
}
internal override int[] Exclude
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => exclude;
}
static Mask() { _instance = new Mask<TInc, TExc>(); }
}
#endregion
#region Filter
public interface IEcsFilter
{
public EcsWorld World { get; }
public Mask Mask { get; }
public IEcsWorld World { get; }
public BakedMask Mask { get; }
public IEcsReadonlyGroup Entities { get; }
public int EntitiesCount { get; }
}
public class EcsFilter : IEcsFilter
{
private readonly EcsWorld _source;
private readonly IEcsWorld _source;
private readonly EcsGroup _entities;
private readonly Mask _mask;
private readonly BakedMask _mask;
#region Properties
public EcsWorld World
public IEcsWorld World
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _source;
}
public Mask Mask
public BakedMask Mask
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _mask;
@ -439,7 +247,7 @@ namespace DCFApixels.DragonECS
#endregion
#region Constrcutors
internal EcsFilter(EcsWorld source, Mask mask, int capasity)
internal EcsFilter(IEcsWorld source, BakedMask mask, int capasity)
{
_source = source;
_mask = mask;

View File

@ -5,7 +5,7 @@ namespace DCFApixels.DragonECS
{
public interface IEcsReadonlyGroup
{
public EcsWorld World { get; }
public IEcsWorld World { get; }
public int Count { get; }
public EcsGroup.Enumerator GetEnumerator();
}
@ -17,7 +17,7 @@ namespace DCFApixels.DragonECS
public class EcsGroup : IEcsGroup
{
private EcsWorld _source;
private IEcsWorld _source;
private SparseSet _entities;
private DelayedOp[] _delayedOps;
@ -26,12 +26,12 @@ namespace DCFApixels.DragonECS
private int _lockCount;
#region Properties
public EcsWorld World => _source;
public IEcsWorld World => _source;
public int Count => _entities.Count;
#endregion
#region Constrcutors
public EcsGroup(EcsWorld world, int entitiesCapacity, int delayedOpsCapacity = 128)
public EcsGroup(IEcsWorld world, int entitiesCapacity, int delayedOpsCapacity = 128)
{
_source = world;
_entities = new SparseSet(entitiesCapacity);

View File

@ -10,28 +10,34 @@ namespace DCFApixels.DragonECS
{
public interface IEcsPool
{
public EcsWorld World { get; }
public IEcsWorld World { get; }
public int ID { get; }
public bool Has(int index);
public void Write(int index);
public void Del(int index);
}
public class EcsPool<T> : IEcsPool
public interface IEcsPool<T> : IEcsPool
where T : struct
{
public ref readonly T Read(int entity);
public new ref T Write(int entity);
}
public class EcsPool<T> : IEcsPool<T>
where T : struct
{
private readonly int _id;
private readonly EcsWorld _source;
private readonly IEcsWorld _source;
private readonly SparseSet _sparseSet;
private T[] _denseItems;
#region Properites
public EcsWorld World => _source;
public IEcsWorld World => _source;
public int ID => _id;
#endregion
#region Constructors
public EcsPool(EcsWorld source, int capacity)
public EcsPool(IEcsWorld source, int capacity)
{
_source = source;
_sparseSet = new SparseSet(capacity);
@ -42,34 +48,36 @@ namespace DCFApixels.DragonECS
#region Read/Write/Has/Del
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref readonly T Read(int index)
public ref readonly T Read(int entity)
{
return ref _denseItems[_sparseSet[index]];
return ref _denseItems[_sparseSet[entity]];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref T Write(int index)
public ref T Write(int entity)
{
if (_sparseSet.Contains(index))
if (_sparseSet.Contains(entity))
{
return ref _denseItems[_sparseSet[index]];
return ref _denseItems[_sparseSet[entity]];
}
else
{
_sparseSet.Add(index);
_sparseSet.Add(entity);
_sparseSet.Normalize(ref _denseItems);
return ref _denseItems[_sparseSet.IndexOf(index)];
_source.OnEntityComponentAdded(entity, _id);
return ref _denseItems[_sparseSet.IndexOf(entity)];
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Has(int index)
public bool Has(int entity)
{
return _sparseSet.IndexOf(index) > 0;
return _sparseSet.IndexOf(entity) > 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Del(int index)
public void Del(int entity)
{
_sparseSet.RemoveAt(index);
_sparseSet.RemoveAt(entity);
_source.OnEntityComponentRemoved(entity, _id);
}
#endregion

View File

@ -19,8 +19,8 @@ namespace DCFApixels.DragonECS
private bool _isDestoryed = false;
private int _worldIdIncrement;
private Dictionary<string, EcsWorld> _worldsDict = new Dictionary<string, EcsWorld>();
private List<EcsWorld> _worlds = new List<EcsWorld>();
private Dictionary<string, IEcsWorld> _worldsDict = new Dictionary<string, IEcsWorld>();
private List<IEcsWorld> _worlds = new List<IEcsWorld>();
private Dictionary<Type, IEcsProcessorsRunner> _runners;
private Dictionary<Type, IEcsProcessorsMessenger> _messengers;
@ -89,11 +89,12 @@ namespace DCFApixels.DragonECS
_allProcessors.Add(system);
return this;
}
public EcsSession AddWorld(string name)
public EcsSession AddWorld<TArchetype>(EcsWorld<TArchetype> world, string name = "")
where TArchetype : IWorldArchetype
{
CheckInitForMethod(nameof(AddWorld));
//_worlds.Add(new EcsWorld(_worldIdIncrement++));
_worlds.Add(new EcsWorld(_worldIdIncrement++));
return this;
}

View File

@ -1,20 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace DCFApixels.DragonECS
{
public abstract class EcsTable
{
internal EcsFilter _filter;
public EcsTable(ref TableBuilder builder) { }
public EcsFilter Filter
{
get => _filter;
}
}
}

View File

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

View File

@ -1,215 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace DCFApixels.DragonECS
{
public class EcsWorldMap
{
}
public class EcsWorld
{
public const int MAX_WORLDS = byte.MaxValue; //Номер последнего мира 254
public const int DEAD_WORLD_ID = byte.MaxValue; //Зарезервированный номер мира для мертвых сущьностей
private byte _id = DEAD_WORLD_ID;
//private float _timeScale;//TODO реализовать собсвенныйтайм склей для разных миров
private IEcsPool[] _pools;
private SparseSet _componentIDToPoolID;
private SparseSet _entities = new SparseSet();
private short[] _gens;
private List<EcsFilter>[] _filtersByIncludedComponents;
private List<EcsFilter>[] _filtersByExcludedComponents;
private EcsFilter[] _filters;
private SparseSet _maskIDToFilterID;
#region Properties
public int ID => _id;
public bool IsAlive => _id != DEAD_WORLD_ID;
public bool IsEmpty => _entities.Count < 0;
#endregion
#region Constructors
public EcsWorld()
{
_pools = new IEcsPool[512];
_entities = new SparseSet(512);
_componentIDToPoolID = new SparseSet(512);
_maskIDToFilterID = new SparseSet(512);
_filters = new EcsFilter[512];
}
#endregion
#region Pools
public EcsPool<T> GetPool<T>()
where T : struct
{
int uniqueID = ComponentType<T>.globalID;
int poolIndex = _componentIDToPoolID.IndexOf(uniqueID);
if (poolIndex >= 0)
{
return (EcsPool<T>)_pools[poolIndex];
}
#if DEBUG
if (_componentIDToPoolID.Count >= ushort.MaxValue)
{
throw new EcsFrameworkException("No more room for new component into this world.");
}
#endif
var pool = new EcsPool<T>(this, 512);
_componentIDToPoolID.Add(uniqueID);
_componentIDToPoolID.Normalize(ref _pools);
_componentIDToPoolID.Normalize(ref _filtersByIncludedComponents);
_componentIDToPoolID.Normalize(ref _filtersByExcludedComponents);
_pools[_componentIDToPoolID.IndexOf(poolIndex)] = pool;
return pool;
}
#endregion
#region Filters
public EcsFilter GetFilter<TMask>(TMask mask) where TMask : Mask
{
if (_maskIDToFilterID.TryAdd(mask.ID, ref _filters))
{
EcsFilter filter = new EcsFilter(this, mask, 512);
_filters[_maskIDToFilterID.IndexOf(mask.ID)] = filter;
return filter;
}
else
{
return _filters[_maskIDToFilterID.IndexOf(mask.ID)];
}
}
#endregion
#region NewEntity
public ent NewEntity()
{
int entityID = _entities.GetFree();
_entities.Normalize(ref _gens);
_gens[entityID]++;
return new ent(entityID, _gens[entityID], _id);
}
#endregion
#region Destroy
public void Destroy()
{
_id = DEAD_WORLD_ID;
}
#endregion
#region IsMaskCompatible/IsMaskCompatibleWithout
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsMaskCompatible(Mask mask, int entity)
{
for (int i = 0, iMax = mask.IncCount; i < iMax; i++)
{
if (!_pools[_componentIDToPoolID[mask.Include[i]]].Has(entity))
{
return false;
}
}
for (int i = 0, iMax = mask.ExcCount; i < iMax; i++)
{
if (_pools[_componentIDToPoolID[mask.Exclude[i]]].Has(entity))
{
return false;
}
}
return true;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsMaskCompatibleWithout(Mask mask, int entity, int otherPoolID)
{
for (int i = 0, iMax = mask.IncCount; i < iMax; i++)
{
int poolID = _componentIDToPoolID[mask.Include[i]];
if (poolID == otherPoolID || !_pools[poolID].Has(entity))
{
return false;
}
}
for (int i = 0, iMax = mask.ExcCount; i < iMax; i++)
{
int poolID = _componentIDToPoolID[mask.Exclude[i]];
if (poolID != otherPoolID && _pools[poolID].Has(entity))
{
return false;
}
}
return true;
}
#endregion
#region EntityChangedReact
internal void OnEntityComponentAdded(int entityID, int changedPoolID)
{
var includeList = _filtersByIncludedComponents[changedPoolID];
var excludeList = _filtersByExcludedComponents[changedPoolID];
if (includeList != null)
{
foreach (var filter in includeList)
{
if (IsMaskCompatible(filter.Mask, entityID))
{
filter.Add(entityID);
}
}
}
if (excludeList != null)
{
foreach (var filter in excludeList)
{
if (IsMaskCompatibleWithout(filter.Mask, entityID, changedPoolID))
{
filter.Remove(entityID);
}
}
}
}
internal void OnEntityComponentRemoved(int entityID, int changedPoolID)
{
var includeList = _filtersByIncludedComponents[changedPoolID];
var excludeList = _filtersByExcludedComponents[changedPoolID];
if (includeList != null)
{
foreach (var filter in includeList)
{
if (IsMaskCompatible(filter.Mask, entityID))
{
filter.Remove(entityID);
}
}
}
if (excludeList != null)
{
foreach (var filter in excludeList)
{
if (IsMaskCompatibleWithout(filter.Mask, entityID, changedPoolID))
{
filter.Add(entityID);
}
}
}
}
#endregion
}
}

260
src/IEcsWorld.cs Normal file
View File

@ -0,0 +1,260 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace DCFApixels.DragonECS
{
public interface IWorldArchetype { }
public struct DefaultArchetype : IWorldArchetype { }
public interface IEcsWorld
{
public const int MAX_WORLDS = byte.MaxValue; //Номер последнего мира 254
public const int DEAD_WORLD_ID = byte.MaxValue; //Зарезервированный номер мира для мертвых сущьностей
//private float _timeScale;//TODO реализовать собсвенныйтайм склей для разных миров
#region Properties
public ushort ID { get; internal set; }
public bool IsAlive { get; }
public bool IsEmpty { get; }
public Type ArchetypeType { get; }
#endregion
public EcsPool<T> GetPool<T>() where T : struct;
public EcsFilter GetFilter<TMask>() where TMask : MaskSingleton<TMask>;
public ent NewEntity();
public void Destroy();
public bool IsMaskCompatible(Mask mask, int entity);
public bool IsMaskCompatibleWithout(Mask mask, int entity, int otherPoolID);
internal void OnEntityComponentAdded(int entityID, int changedPoolID);
internal void OnEntityComponentRemoved(int entityID, int changedPoolID);
}
public class EcsWorld<TArchetype> : IEcsWorld
where TArchetype : IWorldArchetype
{
private ushort _id = IEcsWorld.DEAD_WORLD_ID;
private SparseSet _componentIDToPoolID;
private SparseSet _entities = new SparseSet();
private short[] _gens;
private IEcsPool[] _pools;
private List<EcsFilter>[] _filtersByIncludedComponents;
private List<EcsFilter>[] _filtersByExcludedComponents;
private EcsFilter[] _filters;
#region Properties
public ushort ID => _id;
ushort IEcsWorld.ID { get => _id; set => _id = value; }
public bool IsAlive => _id != IEcsWorld.DEAD_WORLD_ID;
public bool IsEmpty => _entities.Count < 0;
public Type ArchetypeType => typeof(TArchetype);
#endregion
#region Constructors
public EcsWorld()
{
_pools = new IEcsPool[512];
_entities = new SparseSet(512);
_componentIDToPoolID = new SparseSet(512);
_filters = new EcsFilter[512];
}
#endregion
#region GetPool
public EcsPool<T> GetPool<T>() where T : struct
{
int uniqueID = ComponentType<T>.uniqueID;
if (uniqueID >= _pools.Length)
{
Array.Resize(ref _pools, ComponentType.capacity);
Array.Resize(ref _filtersByIncludedComponents, ComponentType.capacity);
Array.Resize(ref _filtersByExcludedComponents, ComponentType.capacity);
}
if (_pools[uniqueID] == null)
{
_pools[uniqueID] = new EcsPool<T>(this, 512);
}
return (EcsPool<T>)_pools[uniqueID];
}
#endregion
#region GetFilter
public EcsFilter GetFilter<TMask>() where TMask : MaskSingleton<TMask>
{
var bakedmask = BakedMask<TArchetype, TMask>.Instance;
if (_filters.Length >= BakedMask<TArchetype>.capacity)
{
Array.Resize(ref _filters, BakedMask<TArchetype>.capacity);
}
if (_filters[bakedmask.UniqueID] == null)
{
_filters[bakedmask.UniqueID] = new EcsFilter(this, bakedmask, 512);
}
return _filters[bakedmask.UniqueID];
}
#endregion
#region IsMaskCompatible/IsMaskCompatibleWithout
public bool IsMaskCompatible(Mask mask, int entity)
{
BakedMask bakedMask = mask.GetBaked<TArchetype>();
for (int i = 0, iMax = bakedMask.IncCount; i < iMax; i++)
{
if (!_pools[_componentIDToPoolID[bakedMask.Inc[i]]].Has(entity))
{
return false;
}
}
for (int i = 0, iMax = bakedMask.ExcCount; i < iMax; i++)
{
if (_pools[_componentIDToPoolID[bakedMask.Exc[i]]].Has(entity))
{
return false;
}
}
return true;
}
public bool IsMaskCompatibleWithout(Mask mask, int entity, int otherPoolID)
{
BakedMask bakedMask = mask.GetBaked<TArchetype>();
for (int i = 0, iMax = bakedMask.IncCount; i < iMax; i++)
{
int poolID = _componentIDToPoolID[bakedMask.Inc[i]];
if (poolID == otherPoolID || !_pools[poolID].Has(entity))
{
return false;
}
}
for (int i = 0, iMax = bakedMask.ExcCount; i < iMax; i++)
{
int poolID = _componentIDToPoolID[bakedMask.Exc[i]];
if (poolID != otherPoolID && _pools[poolID].Has(entity))
{
return false;
}
}
return true;
}
#endregion
#region EntityChangedReact
void IEcsWorld.OnEntityComponentAdded(int entityID, int changedPoolID)
{
var includeList = _filtersByIncludedComponents[changedPoolID];
var excludeList = _filtersByExcludedComponents[changedPoolID];
if (includeList != null)
{
foreach (var filter in includeList)
{
if (IsMaskCompatible(filter.Mask.Mask, entityID))
{
filter.Add(entityID);
}
}
}
if (excludeList != null)
{
foreach (var filter in excludeList)
{
if (IsMaskCompatibleWithout(filter.Mask.Mask, entityID, changedPoolID))
{
filter.Remove(entityID);
}
}
}
}
void IEcsWorld.OnEntityComponentRemoved(int entityID, int changedPoolID)
{
var includeList = _filtersByIncludedComponents[changedPoolID];
var excludeList = _filtersByExcludedComponents[changedPoolID];
if (includeList != null)
{
foreach (var filter in includeList)
{
if (IsMaskCompatible(filter.Mask.Mask, entityID))
{
filter.Remove(entityID);
}
}
}
if (excludeList != null)
{
foreach (var filter in excludeList)
{
if (IsMaskCompatibleWithout(filter.Mask.Mask, entityID, changedPoolID))
{
filter.Add(entityID);
}
}
}
}
#endregion
#region NewEntity
public Entity NewEntity()
{
int entityID = _entities.GetFree();
_entities.Normalize(ref _gens);
_gens[entityID]++;
return new Entity(this, entityID);
}
#endregion
#region Destroy
public void Destroy()
{
_id = IEcsWorld.DEAD_WORLD_ID;
}
#endregion
#region Utils
internal abstract class ComponentType
{
internal static int increment = 1;
internal static int capacity = 512;
}
internal sealed class ComponentType<T> : ComponentType
{
internal static int uniqueID;
static ComponentType()
{
uniqueID = increment++;
#if DEBUG || DCFAECS_NO_SANITIZE_CHECKS
if (increment + 1 > ushort.MaxValue)
{
throw new EcsFrameworkException($"No more room for new component for this {typeof(TArchetype).FullName} IWorldArchetype");
}
#endif
if (increment > capacity)
{
capacity <<= 1;
}
}
}
#endregion
}
}

View File

@ -8,7 +8,7 @@ namespace DCFApixels.DragonECS
[StructLayout(LayoutKind.Sequential, Pack = 0, Size = 8)]
public readonly struct ent : IEquatable<long>, IEquatable<ent>
{
public static readonly long NULL = 0;
public static readonly ent NULL = default;
// id - 32 bits
// gen - 16 bits
@ -23,25 +23,25 @@ namespace DCFApixels.DragonECS
get => (int)(_full >> 32);
}
[EditorBrowsable(EditorBrowsableState.Never)]
public short gen
public ushort gen
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => (short)((_full << 32) >> 48);
get => (ushort)((_full << 32) >> 48);
}
// но чтобы значене default было NULL сульностью, мир хранится в виде ID + 1
[EditorBrowsable(EditorBrowsableState.Never)]
public short world
public ushort world
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => (short)(((_full << 48) >> 48) - 1);
get => (ushort)(((_full << 48) >> 48) - 1);
}
#endregion
#region Constructors
[EditorBrowsable(EditorBrowsableState.Never)]
public ent(int id, short gen, short world)
public ent(int id, short gen, ushort world)
{
_full = ((long)id) << 32;
_full += ((long)gen) << 16;
@ -112,11 +112,11 @@ namespace DCFApixels.DragonECS
}
}
public ref struct Entity
public readonly ref struct Entity
{
internal EcsWorld world;
internal int id;
public Entity(EcsWorld world, int id)
internal readonly IEcsWorld world;
internal readonly int id;
public Entity(IEcsWorld world, ent id)
{
this.world = world;
this.id = id;

View File

@ -1,32 +0,0 @@
namespace DCFApixels.DragonECS
{
public readonly ref struct TableBuilder
{
private readonly EcsWorld _world;
private readonly EcsWorld.Mask _mask;
public TableBuilder(EcsWorld world, EcsWorld.Mask mask)
{
_world = world;
_mask = mask;
}
public EcsPool<T> Cache<T>(mem<T> member)
where T : struct
{
return _world.GetPool(member);
}
public EcsPool<T> Inc<T>(mem<T> member)
where T : struct
{
_mask.Inc(member);
return _world.GetPool(member);
}
public EcsPool<T> Exc<T>(mem<T> member)
where T : struct
{
_mask.Exc(member);
return _world.GetPool(member);
}
}
}

38
src/Utils/BitMask.cs Normal file
View File

@ -0,0 +1,38 @@
using System;
namespace DCFApixels.DragonECS
{
public class BitMask
{
private int[] data;
public int Length { get; private set; }
public BitMask(int length)
{
Length = length;
data = new int[(length + 31) / 32];
}
public void Resize(int newLength)
{
Length = newLength;
Array.Resize(ref data, (newLength + 31) / 32);
}
public void Set1(int index)
{
data[index / 32] |= 1 << (index % 32);
}
public void Set0(int index)
{
data[index / 32] &= ~(1 << (index % 32));
}
public bool Get(int index)
{
return (data[index / 32] & (1 << (index % 32))) != 0;
}
}
}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 3ae306a1fd41f78428c59018eeaf21f3
guid: 88bc1ea51d98c0843a48314fbe00ad9e
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@ -1,98 +0,0 @@
using System;
using System.Runtime.CompilerServices;
namespace DCFApixels.DragonECS
{
internal abstract class ComponentType
{
internal static int increment = 1;
internal static int capacity = 512;
}
internal sealed class ComponentType<T> : ComponentType
{
internal static int globalID;
static ComponentType()
{
globalID = increment++;
if (increment > capacity)
{
capacity <<= 1;
}
}
}
public class ComponentTypeMap
{
private int[] _dense;
private int[] _sparse;
private int _count;
#region Properties
public int Count
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _count;
}
#endregion
#region Constrcutors
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ComponentTypeMap(int denseCapacity = 64)
{
_dense = new int[denseCapacity];
_sparse = new int[ComponentType.capacity];
_count = 0;
}
#endregion
#region Contains
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Contains<T>() => Contains(ComponentType<T>.globalID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private bool Contains(int globalID)
{
return globalID > 0 && globalID < _sparse.Length && _sparse[globalID] > 0;
}
#endregion
#region GetID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int GetID<T>()
{
int globalID = ComponentType<T>.globalID;
if (!Contains(globalID))
{
Add(globalID);
}
return _dense[globalID];
}
#endregion
#region Add
private void Add(int entityID)
{
if (Contains(entityID))
return;
if (++_count >= _dense.Length)
Array.Resize(ref _dense, _dense.Length << 1);
if (entityID > _sparse.Length)
{
int neadedSpace = _sparse.Length;
while (entityID >= neadedSpace)
neadedSpace <<= 1;
Array.Resize(ref _sparse, neadedSpace);
}
_dense[_count] = entityID;
_sparse[entityID] = _count;
}
#endregion
}
}

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -1,63 +0,0 @@
using System;
using System.Collections.Generic;
using DCFApixels;
using UnityEngine;
namespace DCFApixels.DragonECS
{
public class TransformTable : EcsTable
{
public readonly EcsPool<Vector3> position;
public readonly EcsPool<Quaternion> rotation;
public readonly EcsPool<Vector3> scale;
public TransformTable(ref TableBuilder tableBuilder) : base(ref tableBuilder)
{
position = tableBuilder.Inc(Mems.position);
rotation = tableBuilder.Inc(Mems.rotation);
scale = tableBuilder.Inc(Mems.scale);
}
}
public class PositionTable : EcsTable
{
public readonly EcsPool<Vector3> position;
public readonly EcsPool<Quaternion> rotation;
public readonly EcsPool<Vector3> scale;
public PositionTable(ref TableBuilder tableBuilder) : base(ref tableBuilder)
{
position = tableBuilder.Inc(Mems.position);
rotation = tableBuilder.Cache(Mems.rotation);
scale = tableBuilder.Cache(Mems.scale);
}
}
public class RotationTable : EcsTable
{
public readonly EcsPool<Vector3> position;
public readonly EcsPool<Quaternion> rotation;
public readonly EcsPool<Vector3> scale;
public RotationTable(ref TableBuilder tableBuilder) : base(ref tableBuilder)
{
position = tableBuilder.Cache(Mems.position);
rotation = tableBuilder.Inc(Mems.rotation);
scale = tableBuilder.Cache(Mems.scale);
}
}
public class ScaleTable : EcsTable
{
public readonly EcsPool<Vector3> position;
public readonly EcsPool<Quaternion> rotation;
public readonly EcsPool<Vector3> scale;
public ScaleTable(ref TableBuilder tableBuilder) : base(ref tableBuilder)
{
position = tableBuilder.Cache(Mems.position);
rotation = tableBuilder.Cache(Mems.rotation);
scale = tableBuilder.Inc(Mems.scale);
}
}
}

View File

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