Browse Source

improve EGIDMapper

Remove last methods that were still accepting groups as uint
improve comments
fix EntityCollection bug
tags/2.8
sebas77 5 years ago
parent
commit
3599868629
14 changed files with 394 additions and 225 deletions
  1. +1
    -1
      Svelto.Common
  2. +23
    -0
      Svelto.ECS.Components/Svelto.ECS.Components.asmdef
  3. +8
    -13
      Svelto.ECS/DataStructures/TypeSafeDictionary.cs
  4. +14
    -2
      Svelto.ECS/EGIDMapper.cs
  5. +1
    -1
      Svelto.ECS/EnginesRoot.DoubleBufferedEntityViews.cs
  6. +1
    -17
      Svelto.ECS/EnginesRoot.GenericEntityFunctions.cs
  7. +1
    -1
      Svelto.ECS/EntitiesDB.cs
  8. +145
    -129
      Svelto.ECS/EntityCollection.cs
  9. +2
    -2
      Svelto.ECS/EntityStructInitializer.cs
  10. +1
    -1
      Svelto.ECS/ExecuteOnEntitiesDB.cs
  11. +132
    -55
      Svelto.ECS/IEntitiesDB.cs
  12. +0
    -3
      Svelto.ECS/IEntityFunctions.cs
  13. +50
    -0
      Svelto.ECS/README.md
  14. +15
    -0
      Svelto.ECS/Svelto.ECS.asmdef

+ 1
- 1
Svelto.Common

@@ -1 +1 @@
Subproject commit b63d124227ed87367b2f0fcdb4a93833a7c9796b
Subproject commit 7783bce4d3465ed7c8e8d2ba5c48881621cf89b8

+ 23
- 0
Svelto.ECS.Components/Svelto.ECS.Components.asmdef View File

@@ -0,0 +1,23 @@
{
"name": "Svelto.ECS.Components.Unity",
"references": [
"Unity.Mathematics",
"Svelto.ECS",
"Svelto.Common"
],
"optionalUnityReferences": [],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [
{
"name": "com.unity.mathematics",
"expression": "0.0.9",
"define": "UNITY_MATHEMATICS"
}
]
}

+ 8
- 13
Svelto.ECS/DataStructures/TypeSafeDictionary.cs View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Svelto.Common;
@@ -36,7 +36,7 @@ namespace Svelto.ECS.Internal
{
static readonly Type _type = typeof(TValue);
static readonly string _typeName = _type.Name;
static readonly bool HasEgid = typeof(INeedEGID).IsAssignableFrom(_type);
static readonly bool _hasEgid = typeof(INeedEGID).IsAssignableFrom(_type);
public TypeSafeDictionary(uint size) : base(size) { }
public TypeSafeDictionary() {}
@@ -49,10 +49,11 @@ namespace Svelto.ECS.Internal
{
try
{
if (HasEgid)
if (_hasEgid)
{
var needEgid = (INeedEGID)tuple.Value;
needEgid.ID = new EGID(tuple.Key, groupId);
Add(tuple.Key, (TValue) needEgid);
}
else
@@ -75,7 +76,7 @@ namespace Svelto.ECS.Internal
{
var typeSafeDictionary = realDic as TypeSafeDictionary<TValue>;
AddEntityViewToEngines(entityViewEnginesDB, ref typeSafeDictionary.GetDirectValue(value.Key), null,
AddEntityViewToEngines(entityViewEnginesDB, ref typeSafeDictionary.GetValueByRef(value.Key), null,
ref profiler);
}
}
@@ -103,7 +104,7 @@ namespace Svelto.ECS.Internal
///
// entity.ID = EGID.UPDATE_REAL_ID_AND_GROUP(entity.ID, toEntityID.groupID, entityCount);
if (HasEgid)
if (_hasEgid)
{
var needEgid = (INeedEGID)entity;
needEgid.ID = toEntityID.Value;
@@ -217,18 +218,12 @@ namespace Svelto.ECS.Internal
internal ref TValue FindElement(uint entityGidEntityId)
{
#if DEBUG && !PROFILER
if (FindIndex(entityGidEntityId, out var findIndex) == false)
if (TryFindIndex(entityGidEntityId, out var findIndex) == false)
throw new Exception("Entity not found in this group ".FastConcat(typeof(TValue).ToString()));
#else
FindIndex(entityGidEntityId, out var findIndex);
TryFindIndex(entityGidEntityId, out var findIndex);
#endif
return ref _values[findIndex];
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal bool TryFindElementIndex(uint entityGidEntityId, out uint index)
{
return FindIndex(entityGidEntityId, out index);
}
}
}

+ 14
- 2
Svelto.ECS/EGIDMapper.cs View File

@@ -8,9 +8,21 @@ namespace Svelto.ECS
internal TypeSafeDictionary<T> map;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref T Entity(EGID id)
public ref T Entity(uint entityID)
{
return ref map.FindElement(id.entityID);
return ref map.FindElement(entityID);
}
public bool TryQueryEntity(uint entityID, out T @value)
{
if (map.TryFindIndex(entityID, out var index))
{
@value = map.GetDirectValue(index);
return true;
}

@value = default;
return false;
}
}
}

+ 1
- 1
Svelto.ECS/EnginesRoot.DoubleBufferedEntityViews.cs View File

@@ -1,4 +1,4 @@
using Svelto.DataStructures.Experimental;
using Svelto.DataStructures.Experimental;
using EntitiesDB =
Svelto.DataStructures.Experimental.FasterDictionary<uint, System.Collections.Generic.Dictionary<System.Type,
Svelto.ECS.Internal.ITypeSafeDictionary>>;


+ 1
- 17
Svelto.ECS/EnginesRoot.GenericEntityFunctions.cs View File

@@ -15,12 +15,6 @@ namespace Svelto.ECS
_weakReference = weakReference;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void RemoveEntity<T>(uint entityID, uint groupID) where T : IEntityDescriptor, new()
{
RemoveEntity<T>(new EGID(entityID, groupID));
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void RemoveEntity<T>(uint entityID, ExclusiveGroup.ExclusiveGroupStruct groupID) where T :
IEntityDescriptor, new()
@@ -39,11 +33,6 @@ namespace Svelto.ECS
}

public void RemoveEntities<T>(uint groupID) where T : IEntityDescriptor, new()
{
throw new NotImplementedException();
}

public void RemoveEntities<T>(ExclusiveGroup.ExclusiveGroupStruct groupID)
where T : IEntityDescriptor, new()
{
@@ -51,16 +40,11 @@ namespace Svelto.ECS
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void RemoveGroupAndEntities(uint groupID)
public void RemoveGroupAndEntities(ExclusiveGroup.ExclusiveGroupStruct groupID)
{
_weakReference.Target.QueueEntitySubmitOperation(
new EntitySubmitOperation(EntitySubmitOperationType.RemoveGroup, new EGID(), new EGID(0, groupID)));
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void RemoveGroupAndEntities(ExclusiveGroup.ExclusiveGroupStruct groupID)
{
RemoveGroupAndEntities((uint)groupID);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]


+ 1
- 1
Svelto.ECS/EntitiesDB.cs View File

@@ -194,7 +194,7 @@ namespace Svelto.ECS.Internal
if (QueryEntitySafeDictionary(entityGID.groupID, out TypeSafeDictionary<T> safeDictionary) == false)
return null;

if (safeDictionary.TryFindElementIndex(entityGID.entityID, out index) == false)
if (safeDictionary.TryFindIndex(entityGID.entityID, out index) == false)
return null;

return safeDictionary.GetValuesArray(out _);


+ 145
- 129
Svelto.ECS/EntityCollection.cs View File

@@ -13,183 +13,199 @@ namespace Svelto.ECS
_count = count;
}

public EntityIterator<T> GetEnumerator() { return new EntityIterator<T>(_array, _count); }
public EntityIterator<T> GetEnumerator()
{
return new EntityIterator<T>(_array, _count);
}

readonly T[] _array;
readonly T[] _array;
readonly uint _count;
}
public struct EntityCollections<T> where T : struct, IEntityStruct
{
public EntityCollections(IEntitiesDB db, ExclusiveGroup[] groups) : this()

public struct EntityIterator<T> : IEnumerator<T>
{
_db = db;
_groups = groups;
}
public EntityIterator(T[] array, uint count) : this()
{
_array = array;
_count = count;
_index = -1;
}

public EntityGroupsIterator<T> GetEnumerator() { return new EntityGroupsIterator<T>(_db, _groups); }
public bool MoveNext()
{
return ++_index < _count;
}

readonly IEntitiesDB _db;
readonly ExclusiveGroup[] _groups;
public void Reset()
{
_index = -1;
}

public ref T Current => ref _array[_index];

T IEnumerator<T>.Current => throw new NotImplementedException();
object IEnumerator.Current => throw new NotImplementedException();

public void Dispose()
{
}

readonly T[] _array;
readonly uint _count;
int _index;
}
}
public struct EntityCollections<T1, T2> where T1 : struct, IEntityStruct where T2 : struct, IEntityStruct
{
public EntityCollections(IEntitiesDB db, ExclusiveGroup[] groups) : this()
{
_db = db;
_groups = groups;
}

public EntityGroupsIterator<T1, T2> GetEnumerator() { return new EntityGroupsIterator<T1, T2>(_db, _groups); }

readonly IEntitiesDB _db;
readonly ExclusiveGroup[] _groups;
}

public struct EntityGroupsIterator<T> : IEnumerator<T> where T : struct, IEntityStruct

public struct EntityCollections<T> where T : struct, IEntityStruct
{
public EntityGroupsIterator(IEntitiesDB db, ExclusiveGroup[] groups) : this()
public EntityCollections(IEntitiesDB db, ExclusiveGroup[] groups) : this()
{
_db = db;
_groups = groups;
_indexGroup = -1;
_index = -1;
}

public bool MoveNext()
public EntityGroupsIterator<T> GetEnumerator()
{
return new EntityGroupsIterator<T>(_db, _groups);
}

readonly IEntitiesDB _db;
readonly ExclusiveGroup[] _groups;

public struct EntityGroupsIterator<T> : IEnumerator<T> where T : struct, IEntityStruct
{
while (_index + 1 >= _count && ++_indexGroup < _groups.Length)
public EntityGroupsIterator(IEntitiesDB db, ExclusiveGroup[] groups) : this()
{
_db = db;
_groups = groups;
_indexGroup = -1;
_index = -1;
_array = _db.QueryEntities<T>(_groups[_indexGroup], out _count);
}

if (++_index < _count)
public bool MoveNext()
{
return true;
}
while (_index + 1 >= _count && ++_indexGroup < _groups.Length)
{
_index = -1;
_array = _db.QueryEntities<T>(_groups[_indexGroup], out _count);
}

return false;
}

public void Reset()
{
_index = -1;
_indexGroup = -1;
_array = _db.QueryEntities<T>(_groups[0], out _count);
}
return ++_index < _count;
}

public ref T Current => ref _array[_index];
public void Reset()
{
_index = -1;
_indexGroup = -1;
_array = _db.QueryEntities<T>(_groups[0], out _count);
}

T IEnumerator<T>. Current => throw new NotImplementedException();
object IEnumerator.Current => throw new NotImplementedException();
public void Dispose() { }
public ref T Current => ref _array[_index];

readonly IEntitiesDB _db;
readonly ExclusiveGroup[] _groups;
T[] _array;
uint _count;
int _index;
int _indexGroup;
}
T IEnumerator<T>.Current => throw new NotImplementedException();
object IEnumerator.Current => throw new NotImplementedException();

public struct ValueRef<T1, T2>
{
readonly T1[] array1;
readonly T2[] array2;
public void Dispose() {}

readonly uint index;
readonly IEntitiesDB _db;
readonly ExclusiveGroup[] _groups;

public ValueRef(T1[] entity1, T2[] entity2, uint i):this()
{
array1 = entity1;
array2 = entity2;
index = i;
T[] _array;
uint _count;
int _index;
int _indexGroup;
}

public ref T1 Item1 => ref array1[index];
public ref T2 Item2 => ref array2[index];
}
public struct EntityGroupsIterator<T1, T2> : IEnumerator<ValueRef<T1, T2>> where T1 : struct, IEntityStruct where T2 : struct, IEntityStruct

public struct EntityCollections<T1, T2> where T1 : struct, IEntityStruct where T2 : struct, IEntityStruct
{
public EntityGroupsIterator(IEntitiesDB db, ExclusiveGroup[] groups) : this()
public EntityCollections(IEntitiesDB db, ExclusiveGroup[] groups) : this()
{
_db = db;
_groups = groups;
_indexGroup = -1;
_index = -1;
}

public bool MoveNext()
public EntityGroupsIterator<T1, T2> GetEnumerator()
{
while (_index + 1 >= _count && ++_indexGroup < _groups.Length)
return new EntityGroupsIterator<T1, T2>(_db, _groups);
}

readonly IEntitiesDB _db;
readonly ExclusiveGroup[] _groups;

public struct EntityGroupsIterator<T1, T2> : IEnumerator<EntityGroupsIterator<T1, T2>.ValueRef>
where T1 : struct, IEntityStruct
where T2 : struct, IEntityStruct
{
public EntityGroupsIterator(IEntitiesDB db, ExclusiveGroup[] groups) : this()
{
_db = db;
_groups = groups;
_indexGroup = -1;
_index = -1;
_value = new ValueRef<T1, T2>(_db.QueryEntities<T1>(_groups[_indexGroup], out _count),
_db.QueryEntities<T2>(_groups[_indexGroup], out var count1), (uint) _index + 1);

#if DEBUG && !PROFILER
if (_count != count1)
throw new ECSException("number of entities in group doesn't match");
#endif
}

if (++_index < _count)
public bool MoveNext()
{
return true;
while (_index + 1 >= _count && ++_indexGroup < _groups.Length)
{
_index = -1;
_array1 = _db.QueryEntities<T1>(_groups[_indexGroup], out _count);
_array2 = _db.QueryEntities<T2>(_groups[_indexGroup], out var count1);

#if DEBUG && !PROFILER
if (_count != count1)
throw new ECSException("number of entities in group doesn't match");
#endif
}

return ++_index < _count;
}

return false;
}

public void Reset()
{
_index = -1;
_indexGroup = -1;
_value = new ValueRef<T1, T2>(_db.QueryEntities<T1>(_groups[_indexGroup], out _count),
_db.QueryEntities<T2>(_groups[_indexGroup], out var count1), 0);
#if DEBUG && !PROFILER
if (_count != count1)
throw new ECSException("number of entities in group doesn't match");
#endif
}
public void Reset()
{
_index = -1;
_indexGroup = -1;
_array1 = _db.QueryEntities<T1>(_groups[0], out _count);
_array2 = _db.QueryEntities<T2>(_groups[0], out var count1);
#if DEBUG && !PROFILER
if (_count != count1)
throw new ECSException("number of entities in group doesn't match");
#endif
}

public ValueRef<T1, T2> Current => _value;
public ValueRef Current => new ValueRef(_array1, _array2, (uint) _index);

ValueRef<T1, T2> IEnumerator<ValueRef<T1, T2>>. Current => throw new NotImplementedException();
object IEnumerator.Current => throw new NotImplementedException();
public void Dispose() { }
ValueRef IEnumerator<ValueRef>.Current => throw new NotImplementedException();
object IEnumerator.Current => throw new NotImplementedException();

readonly IEntitiesDB _db;
readonly ExclusiveGroup[] _groups;
uint _count;
int _index;
int _indexGroup;
ValueRef<T1, T2> _value;
}
public void Dispose() {}

public struct EntityIterator<T> : IEnumerator<T>
{
public EntityIterator(T[] array, uint count) : this()
{
_array = array;
_count = count;
_index = -1;
}
readonly IEntitiesDB _db;
readonly ExclusiveGroup[] _groups;
uint _count;
int _index;
int _indexGroup;
T2[] _array2;
T1[] _array1;

public bool MoveNext() { return ++_index < _count; }
public void Reset() { _index = -1; }
public struct ValueRef
{
readonly T1[] array1;
readonly T2[] array2;

public ref T Current => ref _array[_index];
readonly uint index;

T IEnumerator<T>. Current => throw new NotImplementedException();
object IEnumerator.Current => throw new NotImplementedException();
public void Dispose() { }
public ValueRef(T1[] entity1, T2[] entity2, uint i) : this()
{
array1 = entity1;
array2 = entity2;
index = i;
}

readonly T[] _array;
readonly uint _count;
int _index;
public ref T1 Item1 => ref array1[index];
public ref T2 Item2 => ref array2[index];
}
}
}
}

+ 2
- 2
Svelto.ECS/EntityStructInitializer.cs View File

@@ -25,8 +25,8 @@ namespace Svelto.ECS
initializer = (T) needEgid;
}

if (dictionary.TryFindElementIndex(ID.entityID, out var findElementIndex))
dictionary.GetValuesArray(out _)[findElementIndex] = initializer;
if (dictionary.TryFindIndex(ID.entityID, out var findElementIndex))
dictionary.GetDirectValue(findElementIndex) = initializer;
}
}


+ 1
- 1
Svelto.ECS/ExecuteOnEntitiesDB.cs View File

@@ -22,7 +22,7 @@ namespace Svelto.ECS.Internal
}

public void ExecuteOnAllEntities
<T, W>(ref W value, Action<T[], ExclusiveGroup.ExclusiveGroupStruct, uint, IEntitiesDB, W> action)
<T, W>(W value, Action<T[], ExclusiveGroup.ExclusiveGroupStruct, uint, IEntitiesDB, W> action)
where T : struct, IEntityStruct
{
var type = typeof(T);


+ 132
- 55
Svelto.ECS/IEntitiesDB.cs View File

@@ -4,33 +4,80 @@ namespace Svelto.ECS
{
public interface IEntitiesDB
{
///////////////////////////////////////////////////
/// Query entities
/// ECS systems are meant to work on a set of Entities. These methods allow to iterate over entity
/// structs inside a given group or an array of groups
///////////////////////////////////////////////////
/// <summary>
/// ECS is meant to work on a set of Entities. Working on a single entity is sometime necessary, but using
/// the following functions inside a loop would be a mistake as performance can be significantly impacted
/// return the buffer and the index of the entity inside the buffer using the input EGID
/// Fast and raw return of entities buffer.
/// </summary>
/// <param name="entityGid"></param>
/// <param name="index"></param>
/// <param name="count"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
bool TryQueryEntitiesAndIndex<T>(EGID entityGid, out uint index, out T[] array) where T : struct, IEntityStruct;
bool TryQueryEntitiesAndIndex
<T>(uint id, ExclusiveGroup.ExclusiveGroupStruct group, out uint index, out T[] array)
T[] QueryEntities<T>(ExclusiveGroup.ExclusiveGroupStruct groupStruct, out uint count)
where T : struct, IEntityStruct;

(T1[], T2[]) QueryEntities<T1, T2>(ExclusiveGroup.ExclusiveGroupStruct groupStruct, out uint count)
where T1 : struct, IEntityStruct where T2 : struct, IEntityStruct;
(T1[], T2[], T3[]) QueryEntities<T1, T2, T3>(ExclusiveGroup.ExclusiveGroupStruct groupStruct, out uint count)
where T1 : struct, IEntityStruct where T2 : struct, IEntityStruct where T3 : struct, IEntityStruct;
/// <summary>
/// ECS is meant to work on a set of Entities. Working on a single entity is sometime necessary, but using
/// the following functions inside a loop would be a mistake as performance can be significantly impacted
/// return the buffer and the index of the entity inside the buffer using the input EGID
/// return entities that can be iterated through the EntityCollection iterator
/// </summary>
/// <param name="entityGid"></param>
/// <param name="index"></param>
/// <param name="groupStruct"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
T[] QueryEntitiesAndIndex<T>(EGID entityGid, out uint index) where T : struct, IEntityStruct;
T[] QueryEntitiesAndIndex<T>(uint id, ExclusiveGroup.ExclusiveGroupStruct group, out uint index)
EntityCollection<T> QueryEntities<T>(ExclusiveGroup.ExclusiveGroupStruct groupStruct)
where T : struct, IEntityStruct;
/// <summary>
/// return entities found in multiple groups, that can be iterated through the EntityCollection iterator
/// This method is useful to write abstracted engines
/// </summary>
/// <param name="groupStruct"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
EntityCollections<T> QueryEntities<T>(ExclusiveGroup[] groups) where T : struct, IEntityStruct;
EntityCollections<T1, T2> QueryEntities<T1, T2>(ExclusiveGroup[] groups)
where T1 : struct, IEntityStruct where T2 : struct, IEntityStruct;
///////////////////////////////////////////////////
/// Query entities regardless the group
/// these methods are necessary to create abstracted engines. Engines that can iterate over entities regardless
/// the group
///////////////////////////////////////////////////

/// <summary>
/// Execute an action on ALL the entities regardless the group. This function doesn't guarantee cache
/// friendliness even if just EntityStructs are used. Safety checks are in place,
/// </summary>
/// <param name="damageableGroups"></param>
/// <param name="action"></param>
/// <typeparam name="T"></typeparam>
void ExecuteOnAllEntities<T>(Action<T[], ExclusiveGroup.ExclusiveGroupStruct, uint, IEntitiesDB> action)
where T : struct, IEntityStruct;

/// <summary>
/// same as above, but can pass some external data to avoid allocations
/// </summary>
/// <param name="value"></param>
/// <param name="action"></param>
/// <typeparam name="T"></typeparam>
/// <typeparam name="W"></typeparam>
void ExecuteOnAllEntities<T, W>(W value,
Action<T[], ExclusiveGroup.ExclusiveGroupStruct, uint, IEntitiesDB, W> action)
where T : struct, IEntityStruct;

///////////////////////////////////////////////////
/// Query single entities
/// ECS systems are meant to work on a set of Entities. Working on a single entity is sometime necessary, hence
/// the following methods
/// However Because of the double hashing required to identify a specific entity, these function are slower than
/// other query methods when used multiple times!
///////////////////////////////////////////////////
/// <summary>
/// QueryUniqueEntity is a contract method that explicitly declare the intention to have just on entity in a
/// specific group, usually used for GUI elements
@@ -39,9 +86,9 @@ namespace Svelto.ECS
/// <typeparam name="T"></typeparam>
/// <returns></returns>
ref T QueryUniqueEntity<T>(ExclusiveGroup.ExclusiveGroupStruct group) where T : struct, IEntityStruct;
/// <summary>
///
/// return a specific entity by reference.
/// </summary>
/// <param name="entityGid"></param>
/// <typeparam name="T"></typeparam>
@@ -50,30 +97,44 @@ namespace Svelto.ECS
ref T QueryEntity<T>(uint id, ExclusiveGroup.ExclusiveGroupStruct group) where T : struct, IEntityStruct;

/// <summary>
/// Fast and raw (therefore not safe) return of entities buffer
/// Modifying a buffer would compromise the integrity of the whole DB
/// so they are meant to be used only in performance critical path
///
///QueryEntitiesAndIndex is useful to optimize cases when multiple entity structs from the same entity must
/// be queried. This is the use case:
///
///ref var ghostPosition = ref entitiesDB.QueryEntitiesAndIndex<PositionEntityStruct>
/// (MockupRenderingGroups.GhostCubeID, out var index)[index];
///ref var ghostScaling = ref entitiesDB.QueryEntities<ScalingEntityStruct>
/// (MockupRenderingGroups.GhostCubeID.groupID, out _)[index];
///ref var ghostRotation = ref entitiesDB.QueryEntities<RotationEntityStruct>
/// (MockupRenderingGroups.GhostCubeID.groupID, out _)[index];
///ref var ghostResource = ref entitiesDB.QueryEntities<GFXPrefabEntityStruct>
/// (MockupRenderingGroups.GhostCubeID.groupID, out _)[index];
///
/// </summary>
/// <param name="count"></param>
/// <param name="entityGid"></param>
/// <param name="index"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
T[] QueryEntities<T>(ExclusiveGroup.ExclusiveGroupStruct groupStruct, out uint count)
T[] QueryEntitiesAndIndex<T>(EGID entityGid, out uint index) where T : struct, IEntityStruct;
T[] QueryEntitiesAndIndex<T>(uint id, ExclusiveGroup.ExclusiveGroupStruct group, out uint index)
where T : struct, IEntityStruct;
(T1[], T2[]) QueryEntities<T1, T2>(ExclusiveGroup.ExclusiveGroupStruct groupStruct, out uint count)
where T1 : struct, IEntityStruct where T2 : struct, IEntityStruct;
(T1[], T2[], T3[]) QueryEntities<T1, T2, T3>(ExclusiveGroup.ExclusiveGroupStruct groupStruct, out uint count)
where T1 : struct, IEntityStruct where T2 : struct, IEntityStruct where T3 : struct, IEntityStruct;
EntityCollection<T> QueryEntities<T>(ExclusiveGroup.ExclusiveGroupStruct groupStruct)
/// <summary>
/// Like QueryEntitiesAndIndex and only way to get an index only if exists
/// </summary>
/// <param name="entityGid"></param>
/// <param name="index"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
bool TryQueryEntitiesAndIndex<T>(EGID entityGid, out uint index, out T[] array) where T : struct, IEntityStruct;
bool TryQueryEntitiesAndIndex
<T>(uint id, ExclusiveGroup.ExclusiveGroupStruct group, out uint index, out T[] array)
where T : struct, IEntityStruct;

EntityCollections<T> QueryEntities<T>(ExclusiveGroup[] groups) where T : struct, IEntityStruct;
EntityCollections<T1, T2> QueryEntities<T1, T2>(ExclusiveGroup[] groups)
where T1 : struct, IEntityStruct where T2 : struct, IEntityStruct;

/// <summary>
/// this version returns a mapped version of the entity array so that is possible to find the
/// index of the entity inside the returned buffer through it's EGID
/// this method returns a mapped version of the entity array so that is possible to work on multiple entities
/// inside the group through their EGID. This version skip a level of indirection so it's a bit faster than
/// using QueryEntity multiple times (with different EGIDs).
/// However mapping can be slow so it must be used for not performance critical paths
/// </summary>
/// <param name="groupID"></param>
@@ -82,24 +143,13 @@ namespace Svelto.ECS
/// <returns></returns>
EGIDMapper<T> QueryMappedEntities<T>(ExclusiveGroup.ExclusiveGroupStruct groupStructId)
where T : struct, IEntityStruct;

/// <summary>
/// Execute an action on ALL the entities regardless the group. This function doesn't guarantee cache
/// friendliness even if just EntityStructs are used.
/// Safety checks are in place
/// </summary>
/// <param name="damageableGroups"></param>
/// <param name="action"></param>
/// <typeparam name="T"></typeparam>
void ExecuteOnAllEntities<T>(Action<T[], ExclusiveGroup.ExclusiveGroupStruct, uint, IEntitiesDB> action)
where T : struct, IEntityStruct;

void ExecuteOnAllEntities<T, W>(ref W value,
Action<T[], ExclusiveGroup.ExclusiveGroupStruct, uint, IEntitiesDB, W> action)
where T : struct, IEntityStruct;

///////////////////////////////////////////////////
/// Utility methods
///////////////////////////////////////////////////
/// <summary>
///
/// check if a specific entity exists
/// </summary>
/// <param name="egid"></param>
/// <typeparam name="T"></typeparam>
@@ -108,7 +158,7 @@ namespace Svelto.ECS
bool Exists(ExclusiveGroup.ExclusiveGroupStruct gid);

/// <summary>
///
/// know if there is any entity struct in a specific group
/// </summary>
/// <param name="group"></param>
/// <typeparam name="T"></typeparam>
@@ -116,18 +166,45 @@ namespace Svelto.ECS
bool HasAny<T>(ExclusiveGroup.ExclusiveGroupStruct groupStruct) where T : struct, IEntityStruct;

/// <summary>
///
/// Count the number of entity structs in a specific group
/// </summary>
/// <param name="groupStruct"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
uint Count<T>(ExclusiveGroup.ExclusiveGroupStruct groupStruct) where T : struct, IEntityStruct;
///////////////////////////////////////////////////
/// Publish entities in the entity stream
/// The Entity Stream is a communication mean based on the Publisher/Consumer model. The pattern is
/// 1) changing an entity
/// 2) publish the entity modified
///////////////////////////////////////////////////

/// <summary>
///
/// Publish an Entity Change, through the Entity Stream linked to this database
/// Use case:
/// public void Add(ref ButtonEntityViewStruct buttonEntityViewStruct)
/// {
/// buttonEntityViewStruct.buttonClick.buttonEvent = new DispatchOnSet<ButtonEvents>(buttonEntityViewStruct.ID);
///
/// buttonEntityViewStruct.buttonClick.buttonEvent.NotifyOnValueSet(_enqueueButtonChange);
/// }
///
/// public void Remove(ref ButtonEntityViewStruct buttonEntityViewStruct)
/// {
/// buttonEntityViewStruct.buttonClick.buttonEvent.StopNotify(_enqueueButtonChange);
/// }
///
/// void EnqueueButtonChange(EGID egid, ButtonEvents value)
/// {
/// entitiesDB.QueryEntity<ButtonEntityStruct>(egid) = new ButtonEntityStruct(egid, value);
///
/// entitiesDB.PublishEntityChange<ButtonEntityStruct>(egid);
/// }
/// </summary>
/// <param name="egid"></param>
/// <typeparam name="T"></typeparam>
void PublishEntityChange<T>(EGID egid) where T : unmanaged, IEntityStruct;

}
}

+ 0
- 3
Svelto.ECS/IEntityFunctions.cs View File

@@ -5,14 +5,11 @@ namespace Svelto.ECS
//being entity ID globally not unique, the group must be specified when
//an entity is removed. Not specifying the group will attempt to remove
//the entity from the special standard group.
void RemoveEntity<T>(uint entityID, uint groupID) where T : IEntityDescriptor, new();
void RemoveEntity<T>(uint entityID, ExclusiveGroup.ExclusiveGroupStruct groupID) where T : IEntityDescriptor, new();
void RemoveEntity<T>(EGID entityegid) where T : IEntityDescriptor, new();
void RemoveEntities<T>(uint groupID) where T : IEntityDescriptor, new();
void RemoveEntities<T>(ExclusiveGroup.ExclusiveGroupStruct groupID) where T : IEntityDescriptor, new();

void RemoveGroupAndEntities(uint groupID);
void RemoveGroupAndEntities(ExclusiveGroup.ExclusiveGroupStruct groupID);
void SwapEntityGroup<T>(uint entityID, ExclusiveGroup.ExclusiveGroupStruct fromGroupID, ExclusiveGroup.ExclusiveGroupStruct toGroupID) where T : IEntityDescriptor, new();


+ 50
- 0
Svelto.ECS/README.md View File

@@ -0,0 +1,50 @@
Svelto Entity Component System for Unity
=====================================

**Note: The alpha stage of Svelto 2.0 is almost completed, so if you are here to experiment with it, please use the current alpha branch**

Real Entity-Component-System for c# and Unity (it can be adapted for other c# platforms too). Enables to write encapsulated, uncoupled, highly efficient, data oriented, cache friendly, multi-threaded, code without pain.

you can find working examples to learn how to use the framework here:

https://github.com/sebas77/Svelto-ECS-Example (unity)

https://github.com/sebas77/Svelto.ECS.Vanilla.Example (.net core and standard)

I advise to clone the example repositories separately from the framework one, both under the same Unity project Assets folder.

relative article:

http://www.sebaslab.com/svelto-ecs-2-0-almost-production-ready/

http://www.sebaslab.com/ecs-1-0/

If you want to know more about the theory and rationale behind this framework:

http://www.sebaslab.com/ioc-container-for-unity3d-part-1/

http://www.sebaslab.com/ioc-container-for-unity3d-part-2/

http://www.sebaslab.com/the-truth-behind-inversion-of-control-part-i-dependency-injection/

http://www.sebaslab.com/the-truth-behind-inversion-of-control-part-ii-inversion-of-control/

http://www.sebaslab.com/the-truth-behind-inversion-of-control-part-iii-entity-component-systems/

http://www.sebaslab.com/the-truth-behind-inversion-of-control-part-iv-dependency-inversion-principle/

http://www.sebaslab.com/the-truth-behind-inversion-of-control-part-v-drifting-away-from-ioc-containers/

new article on optimizations:

http://www.sebaslab.com/svelto-ecs-svelto-tasks-to-write-data-oriented-cache-friendly-multi-threaded-code-in-unity/

Note: if you ever build something with Svelto.ECS that you can share with the community, please do and let me know. Other coders need more examples.

Copyright (c) Sebastiano Mandalà

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 15
- 0
Svelto.ECS/Svelto.ECS.asmdef View File

@@ -0,0 +1,15 @@
{
"name": "Svelto.ECS",
"references": [
"Svelto.Common"
],
"optionalUnityReferences": [],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": []
}

Loading…
Cancel
Save