Browse Source

Svelto ECS 2.8 Beta release

tags/2.8
sebas77 5 years ago
parent
commit
59a24f0698
78 changed files with 1991 additions and 1533 deletions
  1. +16
    -0
      Svelto.ECS.Components/Components/ECSQuaternion.cs
  2. +2
    -2
      Svelto.ECS.Components/Components/ECSRect.cs
  3. +20
    -0
      Svelto.ECS.Components/Components/ECSVector2.cs
  4. +24
    -0
      Svelto.ECS.Components/Components/ECSVector3.cs
  5. +2
    -2
      Svelto.ECS.Components/Components/ECSVector4.cs
  6. +132
    -0
      Svelto.ECS.Components/Components/ExtensionMethods.cs
  7. +44
    -0
      Svelto.ECS.Components/Components/ExtensionMethodsUnity.cs
  8. +50
    -0
      Svelto.ECS.Components/ECSResources/ECSResources.cs
  9. +12
    -0
      Svelto.ECS.Components/ECSResources/StringECSDB.cs
  10. +10
    -0
      Svelto.ECS.Components/EntityStructs/LocalTransformEntityStruct.cs
  11. +0
    -2
      Svelto.ECS.Components/EntityStructs/PositionEntityStruct.cs
  12. +1
    -3
      Svelto.ECS.Components/EntityStructs/RotationEntityStruct.cs
  13. +9
    -0
      Svelto.ECS.Components/EntityStructs/ScalingEntityStruct.cs
  14. +23
    -0
      Svelto.ECS.Components/Svelto.ECS.Components.asmdef
  15. +0
    -4
      Svelto.ECS/.gitignore
  16. +15
    -15
      Svelto.ECS/CheckEntityUtilities.cs
  17. +0
    -13
      Svelto.ECS/Common/Components/ECSVector2.cs
  18. +0
    -14
      Svelto.ECS/Common/Components/ECSVector3.cs
  19. +0
    -36
      Svelto.ECS/Common/Components/ExtensionMethods.cs
  20. +0
    -12
      Svelto.ECS/Common/EntityStructs/InterpolateVector3EntityStruct.cs
  21. +12
    -12
      Svelto.ECS/DBC.cs
  22. +106
    -0
      Svelto.ECS/DataStructures/GroupsList.cs
  23. +165
    -139
      Svelto.ECS/DataStructures/TypeSafeDictionary.cs
  24. +4
    -7
      Svelto.ECS/Dispatcher/DispatchOnChange.cs
  25. +27
    -21
      Svelto.ECS/Dispatcher/DispatchOnSet.cs
  26. +2
    -2
      Svelto.ECS/DynamicEntityDescriptorInfo.cs
  27. +148
    -22
      Svelto.ECS/EGID.cs
  28. +5
    -5
      Svelto.ECS/EGIDMapper.cs
  29. +38
    -24
      Svelto.ECS/EnginesRoot.DoubleBufferedEntityViews.cs
  30. +36
    -39
      Svelto.ECS/EnginesRoot.Engines.cs
  31. +131
    -115
      Svelto.ECS/EnginesRoot.Entities.cs
  32. +0
    -25
      Svelto.ECS/EnginesRoot.GenerateEntitiesStream.cs
  33. +12
    -5
      Svelto.ECS/EnginesRoot.GenericEntityFactory.cs
  34. +53
    -46
      Svelto.ECS/EnginesRoot.GenericEntityFunctions.cs
  35. +65
    -78
      Svelto.ECS/EnginesRoot.Submission.cs
  36. +109
    -163
      Svelto.ECS/EntitiesDB.cs
  37. +9
    -29
      Svelto.ECS/EntityBuilder.CheckFields.cs
  38. +25
    -31
      Svelto.ECS/EntityBuilder.cs
  39. +8
    -0
      Svelto.ECS/EntityBuilder.cs.rej
  40. +195
    -0
      Svelto.ECS/EntityCollection.cs
  41. +28
    -31
      Svelto.ECS/EntityFactory.cs
  42. +1
    -1
      Svelto.ECS/EntityGroupNotFoundException.cs
  43. +11
    -0
      Svelto.ECS/EntityHierarchyStruct.cs
  44. +1
    -1
      Svelto.ECS/EntityInfoView.cs
  45. +1
    -1
      Svelto.ECS/EntityNotFoundException.cs
  46. +41
    -38
      Svelto.ECS/EntityStream.cs
  47. +18
    -13
      Svelto.ECS/EntityStructInitializer.cs
  48. +27
    -13
      Svelto.ECS/EntitySubmitOperation.cs
  49. +3
    -3
      Svelto.ECS/EntityView.cs
  50. +3
    -8
      Svelto.ECS/EntityViewUtility.cs
  51. +9
    -9
      Svelto.ECS/ExclusiveGroup.cs
  52. +19
    -136
      Svelto.ECS/ExecuteOnEntitiesDB.cs
  53. +6
    -5
      Svelto.ECS/Extensions/Unity/GenericEntityDescriptorHolder.cs
  54. +0
    -38
      Svelto.ECS/Extensions/Unity/SveltoEntityFactoryForUnity.cs
  55. +72
    -0
      Svelto.ECS/Extensions/Unity/SveltoGUIHelper.cs
  56. +4
    -1
      Svelto.ECS/Extensions/Unity/UnityEntitySubmissionScheduler.cs
  57. +33
    -62
      Svelto.ECS/GenericEntityDescriptor.cs
  58. +22
    -0
      Svelto.ECS/GenericentityStreamConsumerFactory.cs
  59. +6
    -0
      Svelto.ECS/Hybrid/IEntityViewStruct.cs
  60. +0
    -0
      Svelto.ECS/Hybrid/IImplementor.cs
  61. +6
    -17
      Svelto.ECS/IEngine.cs
  62. +93
    -78
      Svelto.ECS/IEntitiesDB.cs
  63. +1
    -1
      Svelto.ECS/IEntityBuilder.cs
  64. +2
    -1
      Svelto.ECS/IEntityDescriptorHolder.cs
  65. +24
    -9
      Svelto.ECS/IEntityFactory.cs
  66. +9
    -9
      Svelto.ECS/IEntityFunctions.cs
  67. +3
    -0
      Svelto.ECS/IEntityStruct.cs
  68. +0
    -7
      Svelto.ECS/IEntityViewStruct.cs
  69. +0
    -51
      Svelto.ECS/IObsoleteInterfaceDb.cs
  70. +10
    -0
      Svelto.ECS/IReactOnAddAndRemove.cs
  71. +10
    -0
      Svelto.ECS/IReactOnSwap.cs
  72. +0
    -44
      Svelto.ECS/MultiEntitiesEngine.cs
  73. +0
    -45
      Svelto.ECS/MultiEntityViewsEngine.cs
  74. +1
    -1
      Svelto.ECS/Sequencer.cs
  75. +0
    -16
      Svelto.ECS/SingleEntityEngine.cs
  76. +0
    -16
      Svelto.ECS/SingleEntityViewEngine.cs
  77. +6
    -1
      Svelto.ECS/Svelto.ECS.asmdef
  78. +11
    -11
      Svelto.ECS/Svelto.ECS.csproj

+ 16
- 0
Svelto.ECS.Components/Components/ECSQuaternion.cs View File

@@ -0,0 +1,16 @@
namespace Svelto.ECS.Components
{
public struct ECSQuaternion
{
public static readonly ECSQuaternion identity = new ECSQuaternion(0f, 0f, 0f, 1f);
public float x, y, z, w;

public ECSQuaternion(float X, float Y, float Z, float W)
{
x = X;
y = Y;
z = Z;
w = W;
}
}
}

Svelto.ECS/Common/Components/ECSRect.cs → Svelto.ECS.Components/Components/ECSRect.cs View File

@@ -1,7 +1,7 @@
#if UNITY_5 || UNITY_5_3_OR_NEWER
using UnityEngine;

namespace Svelto.ECS.Components
namespace Svelto.ECS.Components.Unity
{
public struct ECSRect
{
@@ -16,4 +16,4 @@ namespace Svelto.ECS.Components
}
}
}
#endif
#endif

+ 20
- 0
Svelto.ECS.Components/Components/ECSVector2.cs View File

@@ -0,0 +1,20 @@
namespace Svelto.ECS.Components
{
public struct ECSVector2
{
public float x, y;

public static readonly ECSVector2 right = new ECSVector2(1f, 0f);
public static readonly ECSVector2 left = new ECSVector2(-1f, 0f);
public static readonly ECSVector2 down = new ECSVector2(0f, -1f);
public static readonly ECSVector2 up = new ECSVector2(0f, 1f);
public static readonly ECSVector2 one = new ECSVector2(1f, 1f);
public static readonly ECSVector2 zero = new ECSVector2(0f, 0f);

public ECSVector2(float X, float Y)
{
x = X;
y = Y;
}
}
}

+ 24
- 0
Svelto.ECS.Components/Components/ECSVector3.cs View File

@@ -0,0 +1,24 @@
namespace Svelto.ECS.Components
{
public struct ECSVector3
{
public float x, y, z;

public static readonly ECSVector3 forward = new ECSVector3(0f, 0f, 1f);
public static readonly ECSVector3 back = new ECSVector3(0f, 0f, -1f);
public static readonly ECSVector3 right = new ECSVector3(1f, 0f, 0f);
public static readonly ECSVector3 left = new ECSVector3(-1f, 0f, 0f);
public static readonly ECSVector3 up = new ECSVector3(0f, 1f, 0f);
public static readonly ECSVector3 down = new ECSVector3(0f, -1f, 0f);

public static readonly ECSVector3 zero = new ECSVector3(0f, 0f, 0f);
public static readonly ECSVector3 one = new ECSVector3(1f, 1f, 1f);

public ECSVector3(float X, float Y, float Z)
{
x = X;
y = Y;
z = Z;
}
}
}

Svelto.ECS/Common/Components/EcsVector4.cs → Svelto.ECS.Components/Components/ECSVector4.cs View File

@@ -1,10 +1,10 @@
namespace Svelto.ECS.Components
{
public struct EcsVector4
public struct ECSVector4
{
public float x, y, z, w;

public EcsVector4(float X, float Y, float Z, float W)
public ECSVector4(float X, float Y, float Z, float W)
{
x = X;
y = Y;

+ 132
- 0
Svelto.ECS.Components/Components/ExtensionMethods.cs View File

@@ -0,0 +1,132 @@
using System;
using System.Runtime.CompilerServices;
using Svelto.ECS.Components;

public static partial class ExtensionMethods
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float SqrMagnitude(in this ECSVector2 a) { return a.x * a.x + a.y * a.y; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float SqrMagnitude(in this ECSVector3 a) { return a.x * a.x + a.y * a.y + a.z * a.z; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Magnitude(in this ECSVector2 a) { return (float) Math.Sqrt(a.SqrMagnitude()); }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Magnitude(in this ECSVector3 a) { return (float) Math.Sqrt(a.SqrMagnitude()); }

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Add(ref this ECSVector3 vector1, in ECSVector3 vector2)
{
vector1.x += vector2.x;
vector1.y += vector2.y;
vector1.z += vector2.z;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Add(ref this ECSVector3 vector1, float x, float y, float z)
{
vector1.x += x;
vector1.y += y;
vector1.z += z;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Set(ref this ECSVector3 vector1, float x, float y, float z)
{
vector1.x = x;
vector1.y = y;
vector1.z = z;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Zero(ref this ECSVector3 vector1)
{
vector1.x = 0;
vector1.y = 0;
vector1.z = 0;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Set(ref this ECSQuaternion quaternion, float x, float y, float z, float w)
{
quaternion.x = x;
quaternion.y = y;
quaternion.z = z;
quaternion.w = w;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Interpolate(ref this ECSVector3 vector, in ECSVector3 vectorS, in ECSVector3 vectorE, float time)
{
vector.x = vectorS.x * (1 - time) + vectorE.x * time;
vector.y = vectorS.y * (1 - time) + vectorE.y * time;
vector.z = vectorS.z * (1 - time) + vectorE.z * time;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Dot(ref this ECSVector3 vector1, in ECSVector3 vector2)
{
return vector1.x * vector2.x + vector1.y * vector2.y + vector1.z * vector2.z;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ECSVector3 Cross(ref this ECSVector3 lhs, in ECSVector3 rhs)
{
return new ECSVector3(lhs.y * rhs.z - lhs.z * rhs.y, lhs.z * rhs.x - lhs.x * rhs.z,
lhs.x * rhs.y - lhs.y * rhs.x);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ECSVector3 Mul(in this ECSQuaternion rotation, in ECSVector3 point)
{
float x = rotation.x * 2F;
float y = rotation.y * 2F;
float z = rotation.z * 2F;
float xx = rotation.x * x;
float yy = rotation.y * y;
float zz = rotation.z * z;
float xy = rotation.x * y;
float xz = rotation.x * z;
float yz = rotation.y * z;
float wx = rotation.w * x;
float wy = rotation.w * y;
float wz = rotation.w * z;

return new ECSVector3((1F - (yy + zz)) * point.x + (xy - wz) * point.y + (xz + wy) * point.z,
(xy + wz) * point.x + (1F - (xx + zz)) * point.y + (yz - wx) * point.z,
(xz - wy) * point.x + (yz + wx) * point.y + (1F - (xx + yy)) * point.z);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Swap(ref this ECSVector3 vector, ref ECSVector3 vectorS)
{
float x = vector.x;
float y = vector.y;
float z = vector.z;

vector.x = vectorS.x;
vector.y = vectorS.y;
vector.z = vectorS.z;

vectorS.x = x;
vectorS.y = y;
vectorS.z = z;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Sub(ref this ECSVector3 vector1, in ECSVector3 vector2)
{
vector1.x -= vector2.x;
vector1.y -= vector2.y;
vector1.z -= vector2.z;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref ECSVector3 Mul(ref this ECSVector3 vector1, float value)
{
vector1.x *= value;
vector1.y *= value;
vector1.z *= value;

return ref vector1;
}
}

+ 44
- 0
Svelto.ECS.Components/Components/ExtensionMethodsUnity.cs View File

@@ -0,0 +1,44 @@
#if UNITY_2018_3_OR_NEWER
using Svelto.ECS.Components;
using UnityEngine;

public static partial class ExtensionMethods
{
public static Vector2 ToVector2(in this ECSVector2 vector) { return new Vector2(vector.x, vector.y); }
public static ECSVector2 ToECSVector2(in this Vector2 vector) { return new ECSVector2(vector.x, vector.y); }

public static Vector3 ToVector3(in this ECSVector3 vector)
{
return new Vector3(vector.x, vector.y, vector.z);
}
public static ECSVector3 ToECSVector3(in this Vector3 vector)
{
return new ECSVector3(vector.x, vector.y, vector.z);
}

public static Quaternion ToQuaternion(in this ECSQuaternion quaternion)
{
return new Quaternion(quaternion.x, quaternion.y, quaternion.z, quaternion.w);
}
public static ECSQuaternion ToECSQuaternion(in this Quaternion quaternion)
{
return new ECSQuaternion(quaternion.x, quaternion.y, quaternion.z, quaternion.w);
}

public static void Set(ref this ECSQuaternion ecsQuaternion, in Quaternion quaternion)
{
ecsQuaternion.x = quaternion.x;
ecsQuaternion.y = quaternion.y;
ecsQuaternion.z = quaternion.z;
ecsQuaternion.w = quaternion.w;
}

public static void Set(ref this ECSVector3 ecsVector3, in Vector3 vector3)
{
ecsVector3.x = vector3.x;
ecsVector3.y = vector3.y;
ecsVector3.z = vector3.z;
}
}

#endif

+ 50
- 0
Svelto.ECS.Components/ECSResources/ECSResources.cs View File

@@ -0,0 +1,50 @@
using Svelto.DataStructures;

namespace Svelto.ECS.Experimental
{
public struct ECSResources<T>
{
internal uint id;
public static implicit operator T(ECSResources<T> ecsString) { return ResourcesECSDB<T>.FromECS(ecsString.id); }
}
static class ResourcesECSDB<T>
{
internal static readonly FasterList<T> _resources = new FasterList<T>();

internal static uint ToECS(T resource)
{
_resources.Add(resource);

return (uint)_resources.Count;
}

public static T FromECS(uint id)
{
if (id - 1 < _resources.Count)
return _resources[(int) id - 1];
return default(T);
}
}

public static class ResourceExtensions
{
public static void Set<T>(ref this ECSResources<T> resource, T newText)
{
if (resource.id != 0)
ResourcesECSDB<T>._resources[(int) resource.id] = newText;
else
resource.id = ResourcesECSDB<T>.ToECS(newText);
}
public static void Set(ref this ECSString resource, string newText)
{
if (resource.id != 0)
ResourcesECSDB<string>._resources[(int) resource.id] = newText;
else
resource.id = ResourcesECSDB<string>.ToECS(newText);
}
}
}

+ 12
- 0
Svelto.ECS.Components/ECSResources/StringECSDB.cs View File

@@ -0,0 +1,12 @@
namespace Svelto.ECS.Experimental
{
public struct ECSString
{
internal uint id;
public static implicit operator string(ECSString ecsString)
{
return ResourcesECSDB<string>.FromECS(ecsString.id);
}
}
}

+ 10
- 0
Svelto.ECS.Components/EntityStructs/LocalTransformEntityStruct.cs View File

@@ -0,0 +1,10 @@
using Svelto.ECS.Components;

namespace Svelto.ECS.EntityStructs
{
public struct LocalTransformEntityStruct : IEntityStruct
{
public ECSVector3 position;
public ECSQuaternion rotation;
}
}

Svelto.ECS/Common/EntityStructs/PositionEntityStruct.cs → Svelto.ECS.Components/EntityStructs/PositionEntityStruct.cs View File

@@ -5,7 +5,5 @@ namespace Svelto.ECS.EntityStructs
public struct PositionEntityStruct : IEntityStruct
{
public ECSVector3 position;

public EGID ID { get; set; }
}
}

Svelto.ECS/Common/EntityStructs/RotationEntityStruct.cs → Svelto.ECS.Components/EntityStructs/RotationEntityStruct.cs View File

@@ -4,8 +4,6 @@ namespace Svelto.ECS.EntityStructs
{
public struct RotationEntityStruct : IEntityStruct
{
public EcsVector4 rotation;
public EGID ID { get; set; }
public ECSQuaternion rotation;
}
}

+ 9
- 0
Svelto.ECS.Components/EntityStructs/ScalingEntityStruct.cs View File

@@ -0,0 +1,9 @@
using Svelto.ECS.Components;

namespace Svelto.ECS.EntityStructs
{
public struct ScalingEntityStruct : IEntityStruct
{
public ECSVector3 scale;
}
}

+ 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"
}
]
}

+ 0
- 4
Svelto.ECS/.gitignore View File

@@ -1,4 +0,0 @@
/EntitySystem/note.txt
/EntitySystem/note.txt.meta
/*.meta
*.meta

+ 15
- 15
Svelto.ECS/CheckEntityUtilities.cs View File

@@ -15,11 +15,10 @@ namespace Svelto.ECS
#endif
void CheckRemoveEntityID(EGID entityID, IEntityDescriptor descriptorEntity)
{

Dictionary<Type, ITypeSafeDictionary> group;
var descriptorEntitiesToBuild = descriptorEntity.entitiesToBuild;
if (_groupEntityDB.TryGetValue(entityID.groupID, out group))
var descriptorEntitiesToBuild = descriptorEntity.entitiesToBuild;
if (_groupEntityDB.TryGetValue(entityID.groupID, out var @group))
{
for (int i = 0; i < descriptorEntitiesToBuild.Length; i++)
{
@@ -38,15 +37,15 @@ namespace Svelto.ECS
#if DISABLE_CHECKS
[Conditional("_CHECKS_DISABLED")]
#endif
void CheckRemoveEntityID(EGID entityID, Type entityType, Dictionary<Type, ITypeSafeDictionary> group, string name)
void CheckRemoveEntityID(EGID entityID, Type entityViewType, Dictionary<Type, ITypeSafeDictionary> group, string name)
{
ITypeSafeDictionary entities;
if (group.TryGetValue(entityType, out entities))
if (group.TryGetValue(entityViewType, out entities))
{
if (entities.Has(entityID.entityID) == false)
{
Console.LogError("Entity ".FastConcat(name, " with not found ID is about to be removed: ")
.FastConcat(entityType.ToString())
.FastConcat(entityViewType.ToString())
.FastConcat(" id: ")
.FastConcat(entityID.entityID)
.FastConcat(" groupid: ")
@@ -56,7 +55,7 @@ namespace Svelto.ECS
else
{
Console.LogError("Entity ".FastConcat(name, " with not found ID is about to be removed: ")
.FastConcat(entityType.ToString())
.FastConcat(entityViewType.ToString())
.FastConcat(" id: ")
.FastConcat(entityID.entityID)
.FastConcat(" groupid: ")
@@ -69,15 +68,15 @@ namespace Svelto.ECS
#endif
void CheckAddEntityID<T>(EGID entityID, T descriptorEntity) where T:IEntityDescriptor
{
Dictionary<Type, ITypeSafeDictionary> group;
var descriptorEntitiesToBuild = descriptorEntity.entitiesToBuild;
var descriptorEntitiesToBuild = descriptorEntity.entitiesToBuild;
//these are the entities added in this frame
if (_groupEntityDB.TryGetValue(entityID.groupID, out group))
if (_groupEntityDB.TryGetValue(entityID.groupID, out var @group))
{
for (int i = 0; i < descriptorEntitiesToBuild.Length; i++)
{
CheckAddEntityID(entityID, descriptorEntitiesToBuild[i].GetEntityType(), group, descriptorEntity.ToString());
CheckAddEntityID(entityID, descriptorEntitiesToBuild[i].GetEntityType(), group,
descriptorEntity.ToString());
}
}
}
@@ -85,15 +84,16 @@ namespace Svelto.ECS
#if DISABLE_CHECKS
[Conditional("_CHECKS_DISABLED")]
#endif
static void CheckAddEntityID(EGID entityID, Type entityType, Dictionary<Type, ITypeSafeDictionary> group, string name)
static void CheckAddEntityID(EGID entityID, Type entityViewType, Dictionary<Type, ITypeSafeDictionary> group,
string name)
{
ITypeSafeDictionary entities;
if (group.TryGetValue(entityType, out entities))
if (group.TryGetValue(entityViewType, out entities))
{
if (entities.Has(entityID.entityID))
{
Console.LogError("Entity ".FastConcat(name, " with used ID is about to be built: ")
.FastConcat(entityType.ToString())
.FastConcat(entityViewType.ToString())
.FastConcat(" id: ")
.FastConcat(entityID.entityID)
.FastConcat(" groupid: ")


+ 0
- 13
Svelto.ECS/Common/Components/ECSVector2.cs View File

@@ -1,13 +0,0 @@
namespace Svelto.ECS.Components
{
public struct ECSVector2
{
public float x, y;

public ECSVector2(float X, float Y)
{
x = X;
y = Y;
}
}
}

+ 0
- 14
Svelto.ECS/Common/Components/ECSVector3.cs View File

@@ -1,14 +0,0 @@
namespace Svelto.ECS.Components
{
public struct ECSVector3
{
public float x, y, z;
public ECSVector3(float X, float Y, float Z)
{
x = X;
y = Y;
z = Z;
}
}
}

+ 0
- 36
Svelto.ECS/Common/Components/ExtensionMethods.cs View File

@@ -1,36 +0,0 @@
#if UNITY_2018_3_OR_NEWER
using UnityEngine;

namespace Svelto.ECS.Components.Unity
{
namespace Svelto.ECS.Components
{
public static class ExtensionMethods
{
public static Vector3 ToVector3(ref this ECSVector3 vector) { return new Vector3(vector.x, vector.y, vector.z); }

public static void Add(ref this ECSVector3 vector1, ref ECSVector3 vector2)
{
vector1.x += vector2.x;
vector1.y += vector2.y;
vector1.z += vector2.z;
}
public static void Add(ref this ECSVector3 vector1, float x, float y, float z)
{
vector1.x += x;
vector1.y += y;
vector1.z += z;
}
public static void Interpolate(ref this ECSVector3 vector, ref ECSVector3 vectorS,
ref ECSVector3 vectorE, float time)
{
vector.x = vectorS.x * (1 - time) + vectorE.x * (time);
vector.y = vectorS.y * (1 - time) + vectorE.y * (time);
vector.z = vectorS.z * (1 - time) + vectorE.z * (time);
}
}
}
}
#endif

+ 0
- 12
Svelto.ECS/Common/EntityStructs/InterpolateVector3EntityStruct.cs View File

@@ -1,12 +0,0 @@
using Svelto.ECS.Components;

namespace Svelto.ECS.EntityStructs
{
public struct InterpolateVector3EntityStruct : IEntityStruct
{
public ECSVector3 starPos, endPos;
public float time;

public EGID ID { get; set; }
}
}

+ 12
- 12
Svelto.ECS/DBC.cs View File

@@ -60,7 +60,7 @@ namespace DBC.ECS
/// <summary>
/// Precondition check.
/// </summary>
#if DISABLE_DBC
#if DISABLE_CHECKS
[Conditional("__NEVER_DEFINED__")]
#endif
public static void Require(bool assertion, string message)
@@ -80,7 +80,7 @@ namespace DBC.ECS
/// Precondition check.
/// </summary>
///
#if DISABLE_DBC
#if DISABLE_CHECKS
[Conditional("__NEVER_DEFINED__")]
#endif
public static void Require(bool assertion, string message, Exception inner)
@@ -100,7 +100,7 @@ namespace DBC.ECS
/// Precondition check.
/// </summary>
///
#if DISABLE_DBC
#if DISABLE_CHECKS
[Conditional("__NEVER_DEFINED__")]
#endif
public static void Require(bool assertion)
@@ -120,7 +120,7 @@ namespace DBC.ECS
/// Postcondition check.
/// </summary>
///
#if DISABLE_DBC
#if DISABLE_CHECKS
[Conditional("__NEVER_DEFINED__")]
#endif
public static void Ensure(bool assertion, string message)
@@ -140,7 +140,7 @@ namespace DBC.ECS
/// Postcondition check.
/// </summary>
///
#if DISABLE_DBC
#if DISABLE_CHECKS
[Conditional("__NEVER_DEFINED__")]
#endif
public static void Ensure(bool assertion, string message, Exception inner)
@@ -160,7 +160,7 @@ namespace DBC.ECS
/// Postcondition check.
/// </summary>
///
#if DISABLE_DBC
#if DISABLE_CHECKS
[Conditional("__NEVER_DEFINED__")]
#endif
public static void Ensure(bool assertion)
@@ -180,7 +180,7 @@ namespace DBC.ECS
/// Invariant check.
/// </summary>
///
#if DISABLE_DBC
#if DISABLE_CHECKS
[Conditional("__NEVER_DEFINED__")]
#endif
public static void Invariant(bool assertion, string message)
@@ -200,7 +200,7 @@ namespace DBC.ECS
/// Invariant check.
/// </summary>
///
#if DISABLE_DBC
#if DISABLE_CHECKS
[Conditional("__NEVER_DEFINED__")]
#endif
public static void Invariant(bool assertion, string message, Exception inner)
@@ -220,7 +220,7 @@ namespace DBC.ECS
/// Invariant check.
/// </summary>
///
#if DISABLE_DBC
#if DISABLE_CHECKS
[Conditional("__NEVER_DEFINED__")]
#endif
public static void Invariant(bool assertion)
@@ -239,7 +239,7 @@ namespace DBC.ECS
/// <summary>
/// Assertion check.
/// </summary>
#if DISABLE_DBC
#if DISABLE_CHECKS
[Conditional("__NEVER_DEFINED__")]
#endif
public static void Assert(bool assertion, string message)
@@ -259,7 +259,7 @@ namespace DBC.ECS
/// Assertion check.
/// </summary>
///
#if DISABLE_DBC
#if DISABLE_CHECKS
[Conditional("__NEVER_DEFINED__")]
#endif
public static void Assert(bool assertion, string message, Exception inner)
@@ -279,7 +279,7 @@ namespace DBC.ECS
/// Assertion check.
/// </summary>
///
#if DISABLE_DBC
#if DISABLE_CHECKS
[Conditional("__NEVER_DEFINED__")]
#endif
public static void Assert(bool assertion)


+ 106
- 0
Svelto.ECS/DataStructures/GroupsList.cs View File

@@ -0,0 +1,106 @@
using System;
using System.Runtime.CompilerServices;
using Svelto.DataStructures;

namespace Svelto.ECS.Internal
{
class GroupList<T>
{
public int Count => _list.Count;

public GroupList()
{
_list = new FasterList<T>();
}

public ref T this[uint index]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => ref _list[index];
}

public GroupListEnumerator<T> GetEnumerator()
{
return new GroupListEnumerator<T>(_list.ToArrayFast(), _list.Count);
}

public T GetOrAdd<TC>(uint location) where TC:class, T, new()
{
if (location >= _list.Count || this[location] == null)
{
var item = new TC();
_list.Add(location, item);
return item;
}

return this[location];
}
public void Clear() { _list.Clear(); }
public void FastClear() { _list.ResetCountToAvoidGC(); }
public bool TryGetValue(uint index, out T value)
{
if (default(T) == null)
{
if (index < _list.Count && this[index] != null)
{
value = this[index];
return true;
}

value = default(T);
return false;
}
else
{
if (index < _list.Count)
{
value = this[index];
return true;
}

value = default(T);
return false;
}
}
public void Add(uint location, T value) { _list.Add(location, value); }

readonly FasterList<T> _list;
}
public struct GroupListEnumerator<T>
{
public ref readonly T Current => ref _buffer[_counter -1];
public uint index => _counter - 1;

public GroupListEnumerator(T[] buffer, int size)
{
_size = size;
_counter = 0;
_buffer = buffer;
}

public bool MoveNext()
{
if (default(T) == null)
{
while (_counter < _size)
{
if (_buffer[_counter] == null)
_counter++;
else
break;
}
}

return _counter++ < _size;
}

readonly T[] _buffer;
uint _counter;
readonly int _size;
}
}

+ 165
- 139
Svelto.ECS/DataStructures/TypeSafeDictionary.cs View File

@@ -1,208 +1,234 @@
using System;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Svelto.Common;
using Svelto.DataStructures;
using Svelto.Common.Internal;
using Svelto.DataStructures;
using Svelto.DataStructures.Experimental;

namespace Svelto.ECS.Internal
{
public interface ITypeSafeDictionary
{
int Count { get; }
ITypeSafeDictionary Create();
void RemoveEntitiesFromEngines(Dictionary<Type, FasterList<IHandleEntityViewEngineAbstracted>>
entityViewEnginesDB, ref PlatformProfiler profiler);

void MoveEntityFromDictionaryAndEngines(EGID fromEntityGid, EGID toEntityID, ITypeSafeDictionary toGroup,
Dictionary<Type, FasterList<IHandleEntityViewEngineAbstracted>>
entityViewEnginesDB, ref PlatformProfiler profiler);
void FillWithIndexedEntities(ITypeSafeDictionary entities);
void AddEntitiesToEngines(Dictionary<Type, FasterList<IHandleEntityViewEngineAbstracted>> entityViewEnginesDB,
ref PlatformProfiler profiler);
void AddCapacity(int size);
int Count { get; }
void RemoveEntitiesFromEngines(
Dictionary<Type, FasterList<IEngine>> entityViewEnginesDB,
ref PlatformProfiler profiler);

void MoveEntityFromDictionaryAndEngines(EGID fromEntityGid, EGID? toEntityID, ITypeSafeDictionary toGroup,
Dictionary<Type, FasterList<IEngine>> engines,
ref PlatformProfiler profiler);

void AddEntitiesFromDictionary(ITypeSafeDictionary entitiesToSubmit, uint groupId);

void AddEntitiesToEngines(Dictionary<Type, FasterList<IEngine>> entityViewEnginesDb,
ITypeSafeDictionary realDic, ref PlatformProfiler profiler);

void SetCapacity(uint size);
void Trim();
void Clear();
bool Has(int entityIdEntityId);
bool Has(uint entityIdEntityId);
}

class TypeSafeDictionary<TValue> : FasterDictionary<int, TValue>, ITypeSafeDictionary where TValue : IEntityStruct
class TypeSafeDictionary<TValue> : FasterDictionary<uint, TValue>, ITypeSafeDictionary where TValue : struct, IEntityStruct
{
public TypeSafeDictionary(int size):base(size)
{}

public TypeSafeDictionary()
{}

public void FillWithIndexedEntities(ITypeSafeDictionary entities)
static readonly Type _type = typeof(TValue);
static readonly string _typeName = _type.Name;
static readonly bool HasEgid = typeof(INeedEGID).IsAssignableFrom(_type);
public TypeSafeDictionary(uint size) : base((uint) size) { }
public TypeSafeDictionary() {}
public void AddEntitiesFromDictionary(ITypeSafeDictionary entitiesToSubmit, uint groupId)
{
int count;
var buffer = (entities as TypeSafeDictionary<TValue>).GetValuesArray(out count);
var typeSafeDictionary = entitiesToSubmit as TypeSafeDictionary<TValue>;
for (var i = 0; i < count; i++)
foreach (var tuple in typeSafeDictionary)
{
int idEntityId = 0;
try
{
idEntityId = buffer[i].ID.entityID;
Add(idEntityId, ref buffer[i]);
if (HasEgid)
{
var needEgid = (INeedEGID)tuple.Value;
needEgid.ID = new EGID(tuple.Key, groupId);
Add(tuple.Key, (TValue) needEgid);
}
else
Add(tuple.Key, ref tuple.Value);
}
catch (Exception e)
{
throw new TypeSafeDictionaryException("trying to add an EntityView with the same ID more than once Entity: ".
FastConcat(typeof(TValue).ToString()).FastConcat("id ").FastConcat(idEntityId), e);
throw new TypeSafeDictionaryException(
"trying to add an EntityView with the same ID more than once Entity: "
.FastConcat(typeof(TValue).ToString()).FastConcat("id ").FastConcat(tuple.Key), e);
}
}
}

public void AddEntitiesToEngines(
Dictionary<Type, FasterList<IHandleEntityViewEngineAbstracted>> entityViewEnginesDB,
Dictionary<Type, FasterList<IEngine>> entityViewEnginesDB,
ITypeSafeDictionary realDic, ref PlatformProfiler profiler)
{
foreach (var value in this)
{
var typeSafeDictionary = realDic as TypeSafeDictionary<TValue>;
AddEntityViewToEngines(entityViewEnginesDB, ref typeSafeDictionary.GetDirectValue(value.Key), null,
ref profiler);
}
}

public bool Has(uint entityIdEntityId) { return ContainsKey(entityIdEntityId); }

public void MoveEntityFromDictionaryAndEngines(EGID fromEntityGid, EGID? toEntityID,
ITypeSafeDictionary toGroup,
Dictionary<Type, FasterList<IEngine>> engines,
ref PlatformProfiler profiler)
{
var values = GetValuesArray(out var count);
//pay attention: even if the entity is passed by ref, it won't be saved back in the database when this
//function is called from the building of an entity. This is by design. Entity structs must be initialized
//through the EntityInitializer method and not with an Add callback.
//however the struct can be modified during an add callback if this happens as consequence of a group swap
for (int i = 0; i < count; i++)
AddEntityViewToEngines(entityViewEnginesDB, ref values[i], ref profiler);
var valueIndex = GetValueIndex(fromEntityGid.entityID);

if (toGroup != null)
{
RemoveEntityViewFromEngines(engines, ref _values[valueIndex], fromEntityGid.groupID, ref profiler);
var toGroupCasted = toGroup as TypeSafeDictionary<TValue>;
ref var entity = ref _values[valueIndex];
var previousGroup = fromEntityGid.groupID;
///
/// NOTE I WOULD EVENTUALLY NEED TO REUSE THE REAL ID OF THE REMOVING ELEMENT
/// SO THAT I CAN DECREASE THE GLOBAL GROUP COUNT
///
// entity.ID = EGID.UPDATE_REAL_ID_AND_GROUP(entity.ID, toEntityID.groupID, entityCount);
if (HasEgid)
{
var needEgid = (INeedEGID)entity;
needEgid.ID = toEntityID.Value;
entity = (TValue) needEgid;
}
var index = toGroupCasted.Add(fromEntityGid.entityID, ref entity);

AddEntityViewToEngines(engines, ref toGroupCasted._values[index], previousGroup,
ref profiler);
}
else
RemoveEntityViewFromEngines(engines, ref _values[valueIndex], null, ref profiler);


Remove(fromEntityGid.entityID);
}

public bool Has(int entityIdEntityId)
public void RemoveEntitiesFromEngines(
Dictionary<Type, FasterList<IEngine>> entityViewEnginesDB,
ref PlatformProfiler profiler)
{
return ContainsKey(entityIdEntityId);
var values = GetValuesArray(out var count);

for (var i = 0; i < count; i++)
RemoveEntityViewFromEngines(entityViewEnginesDB, ref values[i], null, ref profiler);
}

void AddEntityViewToEngines(Dictionary<Type, FasterList<IHandleEntityViewEngineAbstracted>> entityViewEnginesDB,
ref TValue entity, ref PlatformProfiler profiler)
public ITypeSafeDictionary Create() { return new TypeSafeDictionary<TValue>(); }

void AddEntityViewToEngines(Dictionary<Type, FasterList<IEngine>> entityViewEnginesDB,
ref TValue entity,
ExclusiveGroup.ExclusiveGroupStruct? previousGroup,
ref PlatformProfiler profiler)
{
FasterList<IHandleEntityViewEngineAbstracted> entityViewsEngines;
//get all the engines linked to TValue
if (entityViewEnginesDB.TryGetValue(_type, out entityViewsEngines))
for (int i = 0; i < entityViewsEngines.Count; i++)
{
if (!entityViewEnginesDB.TryGetValue(_type, out var entityViewsEngines)) return;

if (previousGroup == null)
{
for (var i = 0; i < entityViewsEngines.Count; i++)
try
{
using (profiler.Sample((entityViewsEngines[i] as EngineInfo).name))
using (profiler.Sample(entityViewsEngines[i], _typeName))
{
(entityViewsEngines[i] as IHandleEntityStructEngine<TValue>).AddInternal(ref entity);
(entityViewsEngines[i] as IReactOnAddAndRemove<TValue>).Add(ref entity);
}
}
catch (Exception e)
{
throw new ECSException("Code crashed inside Add callback ".
FastConcat(typeof(TValue).ToString()).FastConcat("id ").FastConcat(entity.ID.entityID), e);
throw new ECSException(
"Code crashed inside Add callback ".FastConcat(typeof(TValue).ToString()), e);
}
}
}

public void MoveEntityFromDictionaryAndEngines(EGID fromEntityGid, EGID toEntityID, ITypeSafeDictionary toGroup,
Dictionary<Type, FasterList<IHandleEntityViewEngineAbstracted>>
entityViewEnginesDB, ref PlatformProfiler profiler)
{
int count;
var fasterValuesBuffer = GetValuesArray(out count);
var valueIndex = GetValueIndex(fromEntityGid.entityID);
if (entityViewEnginesDB != null)
RemoveEntityViewFromEngines(entityViewEnginesDB, ref fasterValuesBuffer[valueIndex], ref profiler);

if (toGroup != null)
{
var toGroupCasted = toGroup as TypeSafeDictionary<TValue>;
fasterValuesBuffer[valueIndex].ID = toEntityID;
toGroupCasted.Add(toEntityID.entityID, ref fasterValuesBuffer[valueIndex]);
if (entityViewEnginesDB != null)
AddEntityViewToEngines(entityViewEnginesDB, ref toGroupCasted.GetValuesArray(out count)
[toGroupCasted.GetValueIndex(toEntityID.entityID)], ref profiler);
}

Remove(fromEntityGid.entityID);
}

static void RemoveEntityViewFromEngines
(Dictionary<Type, FasterList<IHandleEntityViewEngineAbstracted>> entityViewEnginesDB, ref TValue entity,
ref PlatformProfiler profiler)
{
FasterList<IHandleEntityViewEngineAbstracted> entityViewsEngines;
if (entityViewEnginesDB.TryGetValue(_type, out entityViewsEngines))
for (int i = 0; i < entityViewsEngines.Count; i++)
else
{
for (var i = 0; i < entityViewsEngines.Count; i++)
try
{
using (profiler.Sample((entityViewsEngines[i] as EngineInfo).name, _typeName))
using (profiler.Sample(entityViewsEngines[i], _typeName))
{
(entityViewsEngines[i] as IHandleEntityStructEngine<TValue>).RemoveInternal(ref entity);
(entityViewsEngines[i] as IReactOnSwap<TValue>).MovedTo(ref entity, previousGroup.Value);
}
}
catch (Exception e)
{
throw new ECSException("Code crashed inside Remove callback ".
FastConcat(typeof(TValue).ToString()).FastConcat("id ").FastConcat(entity.ID.entityID), e);
throw new ECSException(
"Code crashed inside Add callback ".FastConcat(typeof(TValue).ToString()), e);
}
}
}
public void RemoveEntitiesFromEngines(Dictionary<Type,
FasterList<IHandleEntityViewEngineAbstracted>> entityViewEnginesDB, ref PlatformProfiler profiler)
{
int count;
TValue[] values = GetValuesArray(out count);

for (int i = 0; i < count; i++)
RemoveEntityViewFromEngines(entityViewEnginesDB, ref values[i], ref profiler);
}
public ITypeSafeDictionary Create()
static void RemoveEntityViewFromEngines(
Dictionary<Type, FasterList<IEngine>> entityViewEnginesDB, ref TValue entity,
ExclusiveGroup.ExclusiveGroupStruct? previousGroup,
ref PlatformProfiler profiler)
{
return new TypeSafeDictionary<TValue>();
}
public bool ExecuteOnEntityView<W>(int entityGidEntityId, ref W value, EntityAction<TValue, W> action)
{
uint findIndex;
if (FindIndex(entityGidEntityId, out findIndex))
{
action(ref _values[findIndex], ref value);
if (!entityViewEnginesDB.TryGetValue(_type, out var entityViewsEngines)) return;

return true;
if (previousGroup == null)
{
for (var i = 0; i < entityViewsEngines.Count; i++)
try
{
using (profiler.Sample(entityViewsEngines[i], _typeName))
(entityViewsEngines[i] as IReactOnAddAndRemove<TValue>).Remove(ref entity);
}
catch (Exception e)
{
throw new ECSException(
"Code crashed inside Remove callback ".FastConcat(typeof(TValue).ToString()), e);
}
}

return false;
}
public bool ExecuteOnEntityView(int entityGidEntityId, EntityAction<TValue> action)
{
uint findIndex;
if (FindIndex(entityGidEntityId, out findIndex))
else
{
action(ref _values[findIndex]);
return true;
for (var i = 0; i < entityViewsEngines.Count; i++)
try
{
using (profiler.Sample(entityViewsEngines[i], _typeName))
(entityViewsEngines[i] as IReactOnSwap<TValue>).MovedFrom(ref entity, previousGroup.Value);
}
catch (Exception e)
{
throw new ECSException(
"Code crashed inside Remove callback ".FastConcat(typeof(TValue).ToString()), e);
}
}

return false;
}
public uint FindElementIndex(int entityGidEntityId)
{
uint findIndex;
if (FindIndex(entityGidEntityId, out findIndex) == false)
throw new Exception("Entity not found in this group");

return findIndex;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal ref TValue FindElement(uint entityGidEntityId)
{
#if DEBUG && !PROFILER
if (FindIndex(entityGidEntityId, out var findIndex) == false)
throw new Exception("Entity not found in this group ".FastConcat(typeof(TValue).ToString()));
#else
FindIndex(entityGidEntityId, out var findIndex);
#endif
return ref _values[findIndex];
}
public bool TryFindElementIndex(int entityGidEntityId, out uint index)

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal bool TryFindElementIndex(uint entityGidEntityId, out uint index)
{
return FindIndex(entityGidEntityId, out index);
}
static readonly Type _type = typeof(TValue);
static readonly string _typeName = _type.Name;
}
}

+ 4
- 7
Svelto.ECS/Dispatcher/DispatchOnChange.cs View File

@@ -1,20 +1,17 @@
using System.Collections.Generic;
using System;

namespace Svelto.ECS
{
public class DispatchOnChange<T> : DispatchOnSet<T> where T:struct
public class DispatchOnChange<T> : DispatchOnSet<T> where T:struct, IEquatable<T>
{
public DispatchOnChange(int senderID) : base(senderID)
public DispatchOnChange(EGID senderID) : base(senderID)
{ }
public DispatchOnChange()
{}

public new T value
{
set
{
if (EqualityComparer<T>.Default.Equals(value, _value) == false)
if (value.Equals(_value) == false)
base.value = value;
}



+ 27
- 21
Svelto.ECS/Dispatcher/DispatchOnSet.cs View File

@@ -5,16 +5,6 @@ namespace Svelto.ECS
{
public class DispatchOnSet<T> where T:struct
{
static ExclusiveGroup OBSOLETE_GROUP = new ExclusiveGroup();
public DispatchOnSet(int senderID)
{
Console.LogWarningDebug("This method is obsolete and shouldn't be used anymore");
_senderID = new EGID(senderID, OBSOLETE_GROUP);
_subscribers = new WeakEvent<EGID, T>();
}

public DispatchOnSet(EGID senderID)
{
_subscribers = new WeakEvent<EGID, T>();
@@ -22,11 +12,6 @@ namespace Svelto.ECS
_senderID = senderID;
}
public DispatchOnSet()
{
_subscribers = new WeakEvent<EGID, T>();
}
public T value
{
set
@@ -36,15 +21,12 @@ namespace Svelto.ECS
_subscribers.Invoke(_senderID, value);
}

get
{
return _value;
}
get => _value;
}
public void NotifyOnValueSet(Action<EGID, T> action)
{
_subscribers += action;
_subscribers += action;
}

public void StopNotify(Action<EGID, T> action)
@@ -53,8 +35,32 @@ namespace Svelto.ECS
}

protected T _value;
readonly EGID _senderID;
internal EGID _senderID;

WeakEvent<EGID, T> _subscribers;
}

public static class DispatchExtensions
{
public static DispatchOnSet<T> Setup<T>(DispatchOnSet<T> dispatcher, EGID entity) where T : struct
{
if (dispatcher == null)
dispatcher = new DispatchOnSet<T>(entity);
else
dispatcher._senderID = entity;

return dispatcher;
}
public static DispatchOnChange<T> Setup<T>(DispatchOnChange<T> dispatcher, EGID entity)
where T : struct, IEquatable<T>
{
if (dispatcher == null)
dispatcher = new DispatchOnChange<T>(entity);
else
dispatcher._senderID = entity;
return dispatcher;
}
}
}

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

@@ -17,9 +17,9 @@ namespace Svelto.ECS
Array.Copy(defaultEntities, 0, entitiesToBuild, 0, length);
Array.Copy(extraEntities, 0, entitiesToBuild, length, extraEntities.Length);

var _builder = new EntityBuilder<EntityInfoView>
var _builder = new EntityBuilder<EntityStructInfoView>
{
_initializer = new EntityInfoView
_initializer = new EntityStructInfoView
{
entitiesToBuild = entitiesToBuild,
type = typeof(TType)


+ 148
- 22
Svelto.ECS/EGID.cs View File

@@ -1,3 +1,4 @@
#if !REAL_ID
using System;
using System.Collections.Generic;
#pragma warning disable 660,661
@@ -6,17 +7,11 @@ namespace Svelto.ECS
{
public struct EGID:IEquatable<EGID>,IEqualityComparer<EGID>,IComparable<EGID>
{
readonly long _GID;
public int entityID
{
get { return (int) (_GID & 0xFFFFFFFF); }
}
public ExclusiveGroup.ExclusiveGroupStruct groupID
{
get { return new ExclusiveGroup.ExclusiveGroupStruct((int) (_GID >> 32)); }
}
readonly ulong _GID;

public uint entityID => (uint) (_GID & 0xFFFFFFFF);

public ExclusiveGroup.ExclusiveGroupStruct groupID => new ExclusiveGroup.ExclusiveGroupStruct((uint) (_GID >> 32));

public static bool operator ==(EGID obj1, EGID obj2)
{
@@ -28,26 +23,24 @@ namespace Svelto.ECS
return obj1._GID != obj2._GID;
}
public EGID(int entityID, ExclusiveGroup.ExclusiveGroupStruct groupID) : this()
public EGID(uint entityID, ExclusiveGroup.ExclusiveGroupStruct groupID) : this()
{
_GID = MAKE_GLOBAL_ID(entityID, groupID);
}
static long MAKE_GLOBAL_ID(int entityId, int groupId)
static ulong MAKE_GLOBAL_ID(uint entityId, uint groupId)
{
return (long)groupId << 32 | ((long)(uint)entityId & 0xFFFFFFFF);
return (ulong)groupId << 32 | ((ulong)entityId & 0xFFFFFFFF);
}

public static explicit operator int(EGID id)
public static explicit operator uint(EGID id)
{
return id.entityID;
}
public static explicit operator long(EGID id)
{
return id._GID;
}

//in the way it's used, ulong must be always the same for each id/group
public static explicit operator ulong(EGID id) { return id._GID; }
public bool Equals(EGID other)
{
return _GID == other._GID;
@@ -68,9 +61,142 @@ namespace Svelto.ECS
return _GID.CompareTo(other._GID);
}
internal EGID(int entityID, int groupID) : this()
internal EGID(uint entityID, uint groupID) : this()
{
_GID = MAKE_GLOBAL_ID(entityID, groupID);
}
}
}
}

#else

using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

#pragma warning disable 660,661

namespace Svelto.ECS
{
public struct EGID:IEquatable<EGID>,IEqualityComparer<EGID>,IComparable<EGID>
{
readonly ulong _GID;
const int idbits = 22; //one bit is reserved
const int groupbits = 20;
const int realidbits = 21;

public EGID(uint entityID, ExclusiveGroup.ExclusiveGroupStruct groupID) : this()
{
DBC.ECS.Check.Require(entityID < bit21, "the entityID value is outside the range, max value: (2^22)-1");
DBC.ECS.Check.Require(groupID < bit20, "the groupID value is outside the range");
_GID = MAKE_GLOBAL_ID(entityID, groupID, 0, 1);
}

const uint bit21 = 0b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0001_1111_1111_1111_1111_1111;
const uint bit22 = 0b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0011_1111_1111_1111_1111_1111;
const uint bit20 = 0b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_1111_1111_1111_1111_1111;

public uint entityID
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return (uint) (_GID & bit22); }
}
public ExclusiveGroup.ExclusiveGroupStruct groupID =>
new ExclusiveGroup.ExclusiveGroupStruct((uint) ((_GID >> idbits) & bit20));

// 1 21 20 1 21
// | | realid | groupid |R| entityID |

static ulong MAKE_GLOBAL_ID(uint entityId, uint groupId, uint realId, byte hasID)
{
var makeGlobalId = (((ulong)realId & bit21) << (idbits+groupbits)) | (((ulong)groupId & bit20) << idbits) | ((ulong)entityId & bit22);

return makeGlobalId | (ulong) (hasID << idbits + groupbits + realidbits);
}

public static explicit operator uint(EGID id)
{
return id.entityID;
}
public static bool operator ==(EGID obj1, EGID obj2)
{
throw new NotSupportedException();
}
public static bool operator !=(EGID obj1, EGID obj2)
{
throw new NotSupportedException();
}

public bool Equals(EGID other)
{
throw new NotSupportedException();
}

public bool Equals(EGID x, EGID y)
{
throw new NotSupportedException();
}
public int CompareTo(EGID other)
{
throw new NotSupportedException();
}

//in the way it's used, ulong must be always the same for each id/group
public static explicit operator ulong(EGID id)
{
throw new NotSupportedException();
}

public int GetHashCode(EGID egid)
{
throw new NotSupportedException();
}
internal EGID(ulong GID) : this()
{
_GID = GID;
}

internal EGID(uint entityID, uint groupID) : this()
{
_GID = MAKE_GLOBAL_ID(entityID, groupID, 0, 1);
}
internal static EGID UPDATE_REAL_ID_AND_GROUP(EGID egid, uint toGroupID, uint realID)
{
if (egid.hasID == 0)
return new EGID(MAKE_GLOBAL_ID(SAFE_ID(realID), toGroupID, realID, 0));
return new EGID(MAKE_GLOBAL_ID(egid.entityID, toGroupID, realID, 1));
}
internal static EGID UPDATE_REAL_ID(EGID egid, uint realID)
{
if (egid.hasID == 0)
return new EGID(MAKE_GLOBAL_ID(SAFE_ID(realID), egid.groupID, realID, 0));
return new EGID(MAKE_GLOBAL_ID(egid.entityID, egid.groupID, realID, 1));
}
internal static EGID CREATE_WITHOUT_ID(uint toGroupID, uint realID)
{
var _GID = MAKE_GLOBAL_ID(SAFE_ID(realID), toGroupID, realID, 0);
return new EGID(_GID);
}

public byte hasID { get { return (byte) (_GID >> idbits + groupbits + realidbits); } }

internal uint realID
{
get { return ((uint)(_GID >> idbits + groupbits)) & bit21; }
}

static uint SAFE_ID(uint u) { return u | (bit21 + 1); }
}
}
#endif

+ 5
- 5
Svelto.ECS/EGIDMapper.cs View File

@@ -1,16 +1,16 @@
using System.Runtime.CompilerServices;
using Svelto.ECS.Internal;

namespace Svelto.ECS
{
public struct EGIDMapper<T> where T : IEntityStruct
public struct EGIDMapper<T> where T : struct, IEntityStruct
{
internal TypeSafeDictionary<T> map;

public ref T entity(EGID id)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref T Entity(EGID id)
{
int count;
var index = map.FindElementIndex(id.entityID);
return ref map.GetValuesArray(out count)[index];
return ref map.FindElement(id.entityID);
}
}
}

+ 38
- 24
Svelto.ECS/EnginesRoot.DoubleBufferedEntityViews.cs View File

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

namespace Svelto.ECS
{
public partial class EnginesRoot
{
class DoubleBufferedEntitiesToAdd<T> where T : FasterDictionary<int, Dictionary<Type, ITypeSafeDictionary>>, new()
internal class DoubleBufferedEntitiesToAdd
{
readonly T _entityViewsToAddBufferA = new T();
readonly T _entityViewsToAddBufferB = new T();

internal DoubleBufferedEntitiesToAdd()
internal void Swap()
{
other = _entityViewsToAddBufferA;
current = _entityViewsToAddBufferB;
Swap(ref current, ref other);
Swap(ref currentEntitiesCreatedPerGroup, ref otherEntitiesCreatedPerGroup);
}

internal T other;
internal T current;
internal void Swap()
void Swap<T>(ref T item1, ref T item2)
{
var toSwap = other;
other = current;
current = toSwap;
T toSwap = item2; item2 = item1; item1 = toSwap;
}

public void ClearOther()
{
foreach (var item in other)
//do not clear the groups created so far, they will be reused
foreach (var groups in other)
{
foreach (var subitem in item.Value)
//do not remove the dictionaries of entities per type created so far, they will be reused
foreach (var entitiesPerType in groups.Value)
{
subitem.Value.Clear();
//clear the dictionary of entities create do far (it won't allocate though)
entitiesPerType.Value.Clear();
}
item.Value.Clear();
}

otherEntitiesCreatedPerGroup.Clear();
}
internal FasterDictionary<uint, uint> currentEntitiesCreatedPerGroup;
internal FasterDictionary<uint, uint> otherEntitiesCreatedPerGroup;
internal EntitiesDB current;
internal EntitiesDB other;

readonly EntitiesDB _entityViewsToAddBufferA = new EntitiesDB();
readonly EntitiesDB _entityViewsToAddBufferB = new EntitiesDB();

readonly FasterDictionary<uint, uint> _entitiesCreatedPerGroupA = new FasterDictionary<uint, uint>();
readonly FasterDictionary<uint, uint> _entitiesCreatedPerGroupB = new FasterDictionary<uint, uint>();
public DoubleBufferedEntitiesToAdd()
{
currentEntitiesCreatedPerGroup = _entitiesCreatedPerGroupA;
otherEntitiesCreatedPerGroup = _entitiesCreatedPerGroupB;
other.Clear();
current = _entityViewsToAddBufferA;
other = _entityViewsToAddBufferB;
}
}
}

+ 36
- 39
Svelto.ECS/EnginesRoot.Engines.cs View File

@@ -20,22 +20,20 @@ namespace Svelto.ECS
/// </summary>
public EnginesRoot(IEntitySubmissionScheduler entityViewScheduler)
{
#if DEBUG && !PROFILER
_entitiesOperationsDebug = new FasterDictionary<long, EntitySubmitOperationType>();
#endif
_entitiesOperations = new FasterList<EntitySubmitOperation>();
_entityEngines = new Dictionary<Type, FasterList<IHandleEntityViewEngineAbstracted>>();
_entitiesOperations = new FasterDictionary<ulong, EntitySubmitOperation>();
_reactiveEnginesAddRemove = new Dictionary<Type, FasterList<IEngine>>();
_reactiveEnginesSwap = new Dictionary<Type, FasterList<IEngine>>();
_enginesSet = new HashSet<IEngine>();
_disposableEngines = new FasterList<IDisposable>();
_transientEntitiesOperations = new FasterList<EntitySubmitOperation>();

_groupEntityDB = new FasterDictionary<int, Dictionary<Type, ITypeSafeDictionary>>();
_groupsPerEntity = new Dictionary<Type, FasterDictionary<int, ITypeSafeDictionary>>();
_groupedEntityToAdd = new DoubleBufferedEntitiesToAdd<FasterDictionary<int, Dictionary<Type, ITypeSafeDictionary>>>();

_entitiesDB = new EntitiesDB(_groupEntityDB, _groupsPerEntity);
_entitiesStream = new EntitiesStream(_entitiesDB);
_groupEntityDB = new FasterDictionary<uint, Dictionary<Type, ITypeSafeDictionary>>();
_groupsPerEntity = new Dictionary<Type, FasterDictionary<uint, ITypeSafeDictionary>>();
_groupedEntityToAdd = new DoubleBufferedEntitiesToAdd();

_entitiesStream = new EntitiesStream();
_entitiesDB = new EntitiesDB(_groupEntityDB, _groupsPerEntity, _entitiesStream);
_scheduler = entityViewScheduler;
_scheduler.onTick = new WeakAction(SubmitEntityViews);
}
@@ -48,18 +46,18 @@ namespace Svelto.ECS

try
{
var viewEngine = engine as IHandleEntityViewEngineAbstracted;

if (viewEngine != null)
CheckEntityViewsEngine(viewEngine);
if (engine is IReactOnAddAndRemove viewEngine)
CheckEntityViewsEngine(viewEngine, _reactiveEnginesAddRemove);
if (engine is IReactOnSwap viewEngineSwap)
CheckEntityViewsEngine(viewEngineSwap, _reactiveEnginesSwap);

_enginesSet.Add(engine);

if (engine is IDisposable)
_disposableEngines.Add(engine as IDisposable);

var queryableEntityViewEngine = engine as IQueryingEntitiesEngine;
if (queryableEntityViewEngine != null)
if (engine is IQueryingEntitiesEngine queryableEntityViewEngine)
{
queryableEntityViewEngine.entitiesDB = _entitiesDB;
queryableEntityViewEngine.Ready();
@@ -75,25 +73,19 @@ namespace Svelto.ECS
}
}
void CheckEntityViewsEngine(IEngine engine)
void CheckEntityViewsEngine(IEngine engine, Dictionary<Type, FasterList<IEngine>> engines)
{
var baseType = engine.GetType().GetBaseType();
var interfaces = engine.GetType().GetInterfaces();

while (baseType != _objectType)
foreach (var interf in interfaces)
{
if (baseType.IsGenericTypeEx())
if (interf.IsGenericTypeEx() && typeof(IReactEngine).IsAssignableFrom(interf))
{
var genericArguments = baseType.GetGenericArgumentsEx();
AddEngine(engine as IHandleEntityViewEngineAbstracted, genericArguments, _entityEngines);
var genericArguments = interf.GetGenericArgumentsEx();

return;
AddEngine(engine, genericArguments, engines);
}

baseType = baseType.GetBaseType();
}

throw new ArgumentException("Not Supported Engine " + engine);
}

static void AddEngine<T>(T engine, Type[] entityViewTypes,
@@ -109,8 +101,7 @@ namespace Svelto.ECS

static void AddEngine<T>(T engine, Dictionary<Type, FasterList<T>> engines, Type type) where T : IEngine
{
FasterList<T> list;
if (engines.TryGetValue(type, out list) == false)
if (engines.TryGetValue(type, out var list) == false)
{
list = new FasterList<T>();

@@ -120,9 +111,10 @@ namespace Svelto.ECS
list.Add(engine);
}

readonly Dictionary<Type, FasterList<IHandleEntityViewEngineAbstracted>> _entityEngines;
readonly HashSet<IEngine> _enginesSet;
readonly FasterList<IDisposable> _disposableEngines;
readonly Dictionary<Type, FasterList<IEngine>> _reactiveEnginesAddRemove;
readonly Dictionary<Type, FasterList<IEngine>> _reactiveEnginesSwap;
readonly HashSet<IEngine> _enginesSet;
readonly FasterList<IDisposable> _disposableEngines;
//one datastructure rule them all:
//split by group
@@ -130,12 +122,17 @@ namespace Svelto.ECS
//to the FasterDictionary capabilities OR it's possible to get a specific entityView indexed by
//ID. This ID doesn't need to be the EGID, it can be just the entityID
//for each group id, save a dictionary indexed by entity type of entities indexed by id
readonly FasterDictionary<int, Dictionary<Type, ITypeSafeDictionary>> _groupEntityDB;
readonly EntitiesDB _entitiesDB;
//ITypeSafeDictionary = Key = entityID, Value = EntityStruct
readonly FasterDictionary<uint, Dictionary<Type, ITypeSafeDictionary>> _groupEntityDB;
//for each entity view type, return the groups (dictionary of entities indexed by entity id) where they are
//found indexed by group id
readonly Dictionary<Type, FasterDictionary<int, ITypeSafeDictionary>> _groupsPerEntity; //yes I am being sarcastic
//found indexed by group id
//EntityViewType //groupID //entityID, EntityStruct
readonly Dictionary<Type, FasterDictionary<uint, ITypeSafeDictionary>> _groupsPerEntity;
readonly EntitiesStream _entitiesStream;
readonly EntitiesDB _entitiesDB;
static readonly Type _objectType = typeof(object);
static readonly Type OBJECT_TYPE = typeof(object);
static readonly Type ENTITY_INFO_VIEW_TYPE = typeof(EntityStructInfoView);
}
}

+ 131
- 115
Svelto.ECS/EnginesRoot.Entities.cs View File

@@ -1,12 +1,13 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Svelto.Common;
using Svelto.DataStructures.Experimental;
using Svelto.ECS.Internal;

namespace Svelto.ECS
{
public partial class EnginesRoot: IDisposable
public partial class EnginesRoot : IDisposable
{
/// <summary>
/// Dispose an EngineRoot once not used anymore, so that all the
@@ -23,7 +24,7 @@ namespace Svelto.ECS
{
try
{
entityList.Value.RemoveEntitiesFromEngines(_entityEngines, ref profiler);
entityList.Value.RemoveEntitiesFromEngines(_reactiveEnginesAddRemove, ref profiler);
}
catch (Exception e)
{
@@ -48,17 +49,17 @@ namespace Svelto.ECS
~EnginesRoot()
{
Console.LogWarning("Engines Root has been garbage collected, don't forget to call Dispose()!");
Dispose();
}

///--------------------------------------------
///
public IEntitiesStream GenerateEntityStream()
public IEntityStreamConsumerFactory GenerateConsumerFactory()
{
return new GenericEntitiesStream(new DataStructures.WeakReference<EnginesRoot>(this));
return new GenericentityStreamConsumerFactory(new DataStructures.WeakReference<EnginesRoot>(this));
}
public IEntityFactory GenerateEntityFactory()
{
return new GenericEntityFactory(new DataStructures.WeakReference<EnginesRoot>(this));
@@ -70,155 +71,171 @@ namespace Svelto.ECS
}

///--------------------------------------------

EntityStructInitializer BuildEntity<T>(EGID entityID, object[] implementors)
where T : IEntityDescriptor, new()
[MethodImpl(MethodImplOptions.AggressiveInlining)]
EntityStructInitializer BuildEntity<T>(EGID entityID, object[] implementors) where T : IEntityDescriptor, new()
{
return BuildEntity(entityID, EntityDescriptorTemplate<T>.descriptor, implementors);
}

EntityStructInitializer BuildEntity<T>(EGID entityID,
T entityDescriptor,
object[] implementors) where T:IEntityDescriptor
[MethodImpl(MethodImplOptions.AggressiveInlining)]
EntityStructInitializer BuildEntity<T>(EGID entityID, T entityDescriptor, object[] implementors)
where T : IEntityDescriptor
{
var descriptorEntitiesToBuild = entityDescriptor.entitiesToBuild;
CheckAddEntityID(entityID, entityDescriptor);

var dic = EntityFactory.BuildGroupedEntities(entityID, _groupedEntityToAdd.current,
var dic = EntityFactory.BuildGroupedEntities(entityID, _groupedEntityToAdd,
descriptorEntitiesToBuild, implementors);
return new EntityStructInitializer(entityID, dic);
}
///--------------------------------------------

void Preallocate<T>(int groupID, int size) where T : IEntityDescriptor, new()
#if REAL_ID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
EntityStructInitializer BuildEntity<T>(ExclusiveGroup.ExclusiveGroupStruct groupID, object[] implementors) where T : IEntityDescriptor, new()
{
//temporary egid, will change during the real submission, needed for the initialization look up
var egid = EGID.CREATE_WITHOUT_ID(groupID, _groupedEntityToAdd.entitiesBuiltThisSubmission++);
var dic = EntityFactory.BuildGroupedEntities(egid, _groupedEntityToAdd.current,
EntityDescriptorTemplate<T>.descriptor.entitiesToBuild, implementors);
return new EntityStructInitializer(egid, dic.groups);
}
#endif

///--------------------------------------------
void Preallocate<T>(uint groupID, uint size) where T : IEntityDescriptor, new()
{
var entityViewsToBuild = EntityDescriptorTemplate<T>.descriptor.entitiesToBuild;
var count = entityViewsToBuild.Length;
var numberOfEntityViews = entityViewsToBuild.Length;
//reserve space in the database
Dictionary<Type, ITypeSafeDictionary> group;
if (_groupEntityDB.TryGetValue(groupID, out group) == false)
if (_groupEntityDB.TryGetValue(groupID, out var @group) == false)
group = _groupEntityDB[groupID] = new Dictionary<Type, ITypeSafeDictionary>();

//reserve space in building buffer
Dictionary<Type, ITypeSafeDictionary> groupBuffer;
if (_groupedEntityToAdd.current.TryGetValue(groupID, out groupBuffer) == false)
groupBuffer = _groupedEntityToAdd.current[groupID] = new Dictionary<Type, ITypeSafeDictionary>();

for (var index = 0; index < count; index++)
for (var index = 0; index < numberOfEntityViews; index++)
{
var entityViewBuilder = entityViewsToBuild[index];
var entityViewType = entityViewBuilder.GetEntityType();
var entityViewType = entityViewBuilder.GetEntityType();

ITypeSafeDictionary dbList;
if (group.TryGetValue(entityViewType, out dbList) == false)
if (group.TryGetValue(entityViewType, out var dbList) == false)
group[entityViewType] = entityViewBuilder.Preallocate(ref dbList, size);
else
dbList.AddCapacity(size);
if (groupBuffer.TryGetValue(entityViewType, out dbList) == false)
groupBuffer[entityViewType] = entityViewBuilder.Preallocate(ref dbList, size);
else
dbList.AddCapacity(size);
dbList.SetCapacity(size);
if (_groupsPerEntity.TryGetValue(entityViewType, out var groupedGroup) == false)
groupedGroup = _groupsPerEntity[entityViewType] = new FasterDictionary<uint, ITypeSafeDictionary>();
groupedGroup[groupID] = dbList;
}
}
///--------------------------------------------
///
void MoveEntity(IEntityBuilder[] entityBuilders, EGID entityGID, Type originalDescriptorType, EGID toEntityGID,
Dictionary<Type, ITypeSafeDictionary> toGroup = null)
void MoveEntity(IEntityBuilder[] entityBuilders, EGID fromEntityGID, Type originalDescriptorType, EGID? toEntityGID)
{
var profiler = new PlatformProfiler();
using (profiler.StartNewSession("Move Entity"))
{
//for each entity view generated by the entity descriptor
Dictionary<Type, ITypeSafeDictionary> fromGroup;

if (_groupEntityDB.TryGetValue(entityGID.groupID, out fromGroup) == false)
throw new ECSException("from group not found eid: "
.FastConcat(entityGID.entityID).FastConcat(" group: ")
.FastConcat(entityGID.groupID));

ITypeSafeDictionary entityInfoViewDic;
EntityInfoView entityInfoView = default;
if (_groupEntityDB.TryGetValue(fromEntityGID.groupID, out var fromGroup) == false)
throw new ECSException("from group not found eid: ".FastConcat(fromEntityGID.entityID)
.FastConcat(" group: ").FastConcat(fromEntityGID.groupID));

//Check if there is an EntityInfoView linked to this entity, if so it's a DynamicEntityDescriptor!
bool correctEntityDescriptorFound = true;
if (fromGroup.TryGetValue(_entityInfoView, out entityInfoViewDic)
&& (entityInfoViewDic as TypeSafeDictionary<EntityInfoView>).TryGetValue
(entityGID.entityID, out entityInfoView) &&
(correctEntityDescriptorFound = entityInfoView.type == originalDescriptorType))

EntityStructInfoView entityInfoView = default;
if (fromGroup.TryGetValue(ENTITY_INFO_VIEW_TYPE, out var entityInfoViewDic) &&
(entityInfoViewDic as TypeSafeDictionary<EntityStructInfoView>).TryGetValue(
fromEntityGID.entityID, out entityInfoView) && (correctEntityDescriptorFound =
entityInfoView.type == originalDescriptorType))
{
var entitiesToMove = entityInfoView.entitiesToBuild;

Dictionary<Type, ITypeSafeDictionary> toGroup = null;

if (toEntityGID != null)
{
var toGroupID = toEntityGID.Value.groupID;
if (_groupEntityDB.TryGetValue(toGroupID, out toGroup) == false)
toGroup = _groupEntityDB[toGroupID] = new Dictionary<Type, ITypeSafeDictionary>();
}

for (int i = 0; i < entitiesToMove.Length; i++)
MoveEntityView(entityGID, toEntityGID, toGroup, fromGroup, entitiesToMove[i].GetEntityType(), profiler);
MoveEntityView(fromEntityGID, toEntityGID, toGroup, ref fromGroup,
entitiesToMove[i].GetEntityType(), profiler);
}
//otherwise it's a normal static entity descriptor
else
{
#if DEBUG && !PROFILER
if (correctEntityDescriptorFound == false)
#if RELAXED_ECS
Console.LogError(INVALID_DYNAMIC_DESCRIPTOR_ERROR
.FastConcat(" ID ").FastConcat(entityGID.entityID)
.FastConcat(" group ID ").FastConcat(entityGID.groupID).FastConcat(
" descriptor found: ", entityInfoView.type.Name,
" descriptor Excepted ", originalDescriptorType.Name));
#else
throw new ECSException(INVALID_DYNAMIC_DESCRIPTOR_ERROR.FastConcat(" ID ").FastConcat(entityGID.entityID)
.FastConcat(" group ID ").FastConcat(entityGID.groupID).FastConcat(
throw new ECSException(INVALID_DYNAMIC_DESCRIPTOR_ERROR.FastConcat(" ID ").FastConcat(fromEntityGID.entityID)
.FastConcat(" group ID ").FastConcat(fromEntityGID.groupID).FastConcat(
" descriptor found: ", entityInfoView.type.Name, " descriptor Excepted ",
originalDescriptorType.Name));
#endif
#endif

Dictionary<Type, ITypeSafeDictionary> toGroup = null;
if (toEntityGID != null)
{
var toGroupID = toEntityGID.Value.groupID;
if (_groupEntityDB.TryGetValue(toGroupID, out toGroup) == false)
toGroup = _groupEntityDB[toGroupID] = new Dictionary<Type, ITypeSafeDictionary>();
}

for (var i = 0; i < entityBuilders.Length; i++)
MoveEntityView(entityGID, toEntityGID, toGroup, fromGroup, entityBuilders[i].GetEntityType(), profiler);
MoveEntityView(fromEntityGID, toEntityGID, toGroup, ref fromGroup,
entityBuilders[i].GetEntityType(), profiler);
}
}
}

void MoveEntityView(EGID entityGID, EGID toEntityGID, Dictionary<Type, ITypeSafeDictionary> toGroup,
Dictionary<Type, ITypeSafeDictionary> fromGroup, Type entityType, PlatformProfiler profiler)
void MoveEntityView(EGID entityGID, EGID? toEntityGID, Dictionary<Type, ITypeSafeDictionary> toGroup,
ref Dictionary<Type, ITypeSafeDictionary> fromGroup, Type entityViewType, PlatformProfiler profiler)
{
ITypeSafeDictionary fromTypeSafeDictionary;
if (fromGroup.TryGetValue(entityType, out fromTypeSafeDictionary) == false)
if (fromGroup.TryGetValue(entityViewType, out var fromTypeSafeDictionary) == false)
{
throw new ECSException("no entities in from group eid: ".FastConcat(entityGID.entityID).FastConcat(" group: ").FastConcat(entityGID.groupID));
throw new ECSException("no entities in from group eid: ".FastConcat(entityGID.entityID)
.FastConcat(" group: ").FastConcat(entityGID.groupID));
}
ITypeSafeDictionary dictionaryOfEntities         = null;
ITypeSafeDictionary toEntitiesDictionary = null;

//in case we want to move to a new group, otherwise is just a remove
if (toGroup != null)
if (toEntityGID != null)
{
if (toGroup.TryGetValue(entityType, out dictionaryOfEntities) == false)
if (toGroup.TryGetValue(entityViewType, out toEntitiesDictionary) == false)
{
dictionaryOfEntities = fromTypeSafeDictionary.Create();
toGroup.Add(entityType, dictionaryOfEntities);
toEntitiesDictionary = fromTypeSafeDictionary.Create();
toGroup.Add(entityViewType, toEntitiesDictionary);
}

FasterDictionary<int, ITypeSafeDictionary> groupedGroup;
if (_groupsPerEntity.TryGetValue(entityType, out groupedGroup) == false)
groupedGroup = _groupsPerEntity[entityType] = new FasterDictionary<int, ITypeSafeDictionary>();
groupedGroup[toEntityGID.groupID] = dictionaryOfEntities;
if (_groupsPerEntity.TryGetValue(entityViewType, out var groupedGroup) == false)
groupedGroup = _groupsPerEntity[entityViewType] = new FasterDictionary<uint, ITypeSafeDictionary>();

groupedGroup[toEntityGID.Value.groupID] = toEntitiesDictionary;
}

if (fromTypeSafeDictionary.Has(entityGID.entityID) == false)
{
throw new EntityNotFoundException(entityGID.entityID, entityGID.groupID, entityType);
throw new EntityNotFoundException(entityGID, entityViewType);
}
fromTypeSafeDictionary.MoveEntityFromDictionaryAndEngines(entityGID, toEntityGID, dictionaryOfEntities,
_entityEngines, ref profiler);

fromTypeSafeDictionary.MoveEntityFromDictionaryAndEngines(entityGID, toEntityGID,
toEntitiesDictionary,
toEntityGID == null ? _reactiveEnginesAddRemove :
_reactiveEnginesSwap,
ref profiler);

if (fromTypeSafeDictionary.Count == 0) //clean up
{
_groupsPerEntity[entityType].Remove(entityGID.groupID);
_groupsPerEntity[entityViewType].Remove(entityGID.groupID);

//I don't remove the group if empty on purpose, in case it needs to be reused however I trim it to save
//memory
@@ -226,24 +243,25 @@ namespace Svelto.ECS
}
}

void RemoveGroupAndEntitiesFromDB(int groupID, Type entityDescriptor)
void RemoveGroupAndEntitiesFromDB(uint groupID, Type entityDescriptor)
{
/* var profiler = new PlatformProfiler();
using (profiler.StartNewSession("Remove Group Of Entities"))
{
FasterDictionary<int, ITypeSafeDictionary> @group;
if (_groupsPerEntity.TryGetValue(entityDescriptor, out group))
{
if (group.TryGetValue())
foreach (var entity in group)
{
MoveEntity(entity.);
}
}
}*/
throw new NotImplementedException();
/* var profiler = new PlatformProfiler();
using (profiler.StartNewSession("Remove Group Of Entities"))
{
FasterDictionary<int, ITypeSafeDictionary> @group;
if (_groupsPerEntity.TryGetValue(entityDescriptor, out group))
{
if (group.TryGetValue())
foreach (var entity in group)
{
MoveEntity(entity.);
}
}
}*/
}

void RemoveGroupAndEntitiesFromDB(int groupID)
void RemoveGroupAndEntitiesFromDB(uint groupID)
{
var profiler = new PlatformProfiler();
using (profiler.StartNewSession("Remove Group"))
@@ -252,7 +270,7 @@ namespace Svelto.ECS
foreach (var dictionaryOfEntities in dictionariesOfEntities)
{
var platformProfiler = profiler;
dictionaryOfEntities.Value.RemoveEntitiesFromEngines(_entityEngines, ref platformProfiler);
dictionaryOfEntities.Value.RemoveEntitiesFromEngines(_reactiveEnginesAddRemove, ref platformProfiler);
var groupedGroupOfEntities = _groupsPerEntity[dictionaryOfEntities.Key];
groupedGroupOfEntities.Remove(groupID);
}
@@ -264,25 +282,23 @@ namespace Svelto.ECS
}

///--------------------------------------------
void SwapEntityGroup(IEntityBuilder[] builders, Type originalEntityDescriptor, EGID fromEntityID, EGID toEntityID)
void SwapEntityGroup(IEntityBuilder[] builders, Type originalEntityDescriptor, EGID fromEntityID,
EGID toEntityID)
{
DBC.ECS.Check.Require(fromEntityID != toEntityID, "the entity destionation EGID is equal to the source EGID");

Dictionary<Type, ITypeSafeDictionary> toGroup;
DBC.ECS.Check.Require(fromEntityID.groupID != toEntityID.groupID,
"entity group is the same of the destination group");

if (_groupEntityDB.TryGetValue(toEntityID.groupID, out toGroup) == false)
toGroup = _groupEntityDB[toEntityID.groupID] = new Dictionary<Type, ITypeSafeDictionary>();
MoveEntity(builders, fromEntityID, originalEntityDescriptor, toEntityID);
}

MoveEntity(builders, fromEntityID, originalEntityDescriptor, toEntityID, toGroup);
internal Consumer<T> GenerateConsumer<T>(string name, int capacity) where T : unmanaged, IEntityStruct
{
return _entitiesStream.GenerateConsumer<T>(name, capacity);
}

readonly EntitiesStream _entitiesStream;
readonly Type _entityInfoView = typeof(EntityInfoView);
const string INVALID_DYNAMIC_DESCRIPTOR_ERROR = "Found an entity requesting an invalid dynamic descriptor, this " +
"can happen only if you are building different entities with the " +
"same ID in the same group! The operation will continue using" +
"the base descriptor only ";
const string INVALID_DYNAMIC_DESCRIPTOR_ERROR =
"Found an entity requesting an invalid dynamic descriptor, this " +
"can happen only if you are building different entities with the " +
"same ID in the same group! The operation will continue using" + "the base descriptor only ";
}
}

+ 0
- 25
Svelto.ECS/EnginesRoot.GenerateEntitiesStream.cs View File

@@ -1,25 +0,0 @@
namespace Svelto.ECS
{
public partial class EnginesRoot
{
class GenericEntitiesStream : IEntitiesStream
{
public GenericEntitiesStream(DataStructures.WeakReference<EnginesRoot> weakReference)
{
_weakEngine = weakReference;
}
public Consumer<T> GenerateConsumer<T>(int capacity) where T : unmanaged, IEntityStruct
{
return _weakEngine.Target._entitiesStream.GenerateConsumer<T>(capacity);
}

public void PublishEntity<T>(EGID id) where T : unmanaged, IEntityStruct
{
_weakEngine.Target._entitiesStream.PublishEntity<T>(id);
}
readonly DataStructures.WeakReference<EnginesRoot> _weakEngine;
}
}
}

+ 12
- 5
Svelto.ECS/EnginesRoot.GenericEntityFactory.cs View File

@@ -9,9 +9,9 @@
_weakEngine = weakReference;
}

public EntityStructInitializer BuildEntity<T>(int entityID, ExclusiveGroup.ExclusiveGroupStruct groupStructId, object[] implementors) where T : IEntityDescriptor, new()
public EntityStructInitializer BuildEntity<T>(uint entityID, ExclusiveGroup.ExclusiveGroupStruct groupStructId, object[] implementors) where T : IEntityDescriptor, new()
{
return _weakEngine.Target.BuildEntity<T>(new EGID(entityID, (int)groupStructId), implementors);
return _weakEngine.Target.BuildEntity<T>(new EGID(entityID, groupStructId), implementors);
}

public EntityStructInitializer BuildEntity<T>(EGID egid, object[] implementors) where T : IEntityDescriptor, new()
@@ -19,17 +19,24 @@
return _weakEngine.Target.BuildEntity<T>(egid, implementors);
}

#if REAL_ID
public EntityStructInitializer BuildEntity<T>(ExclusiveGroup.ExclusiveGroupStruct groupID, object[] implementors = null) where T : IEntityDescriptor, new()
{
return _weakEngine.Target.BuildEntity<T>(groupID, implementors);
}
#endif

public EntityStructInitializer BuildEntity<T>(EGID egid, T entityDescriptor, object[] implementors) where T:IEntityDescriptor
{
return _weakEngine.Target.BuildEntity(egid, entityDescriptor, implementors);
}

public EntityStructInitializer BuildEntity<T>(int entityID, ExclusiveGroup.ExclusiveGroupStruct groupStructId, T descriptorEntity, object[] implementors) where T:IEntityDescriptor
public EntityStructInitializer BuildEntity<T>(uint entityID, ExclusiveGroup.ExclusiveGroupStruct groupStructId, T descriptorEntity, object[] implementors) where T:IEntityDescriptor
{
return _weakEngine.Target.BuildEntity(new EGID(entityID, (int)groupStructId), descriptorEntity, implementors);
return _weakEngine.Target.BuildEntity(new EGID(entityID, groupStructId), descriptorEntity, implementors);
}
public void PreallocateEntitySpace<T>(ExclusiveGroup.ExclusiveGroupStruct groupStructId, int size) where T : IEntityDescriptor, new()
public void PreallocateEntitySpace<T>(ExclusiveGroup.ExclusiveGroupStruct groupStructId, uint size) where T : IEntityDescriptor, new()
{
_weakEngine.Target.Preallocate<T>(groupStructId, size);
}


+ 53
- 46
Svelto.ECS/EnginesRoot.GenericEntityFunctions.cs View File

@@ -1,11 +1,12 @@
using System;
using System.Runtime.CompilerServices;
using Svelto.ECS.Internal;

namespace Svelto.ECS
{
public partial class EnginesRoot
{
class GenericEntityFunctions : IEntityFunctions
sealed class GenericEntityFunctions : IEntityFunctions
{
readonly DataStructures.WeakReference<EnginesRoot> _weakReference;

@@ -14,90 +15,98 @@ namespace Svelto.ECS
_weakReference = weakReference;
}

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

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

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void RemoveEntity<T>(EGID entityEGID) where T : IEntityDescriptor, new()
{
_weakReference.Target.CheckRemoveEntityID(entityEGID, EntityDescriptorTemplate<T>.descriptor);

_weakReference.Target.QueueEntitySubmitOperation<T>(
new EntitySubmitOperation(EntitySubmitOperationType.Remove, entityEGID.entityID, entityEGID.entityID,
entityEGID.groupID,
-1, EntityDescriptorTemplate<T>.descriptor.entitiesToBuild, typeof(T)));
new EntitySubmitOperation(EntitySubmitOperationType.Remove, entityEGID, entityEGID,
EntityDescriptorTemplate<T>.descriptor.entitiesToBuild, typeof(T)));
}

public void RemoveEntities<T>(int groupID) where T : IEntityDescriptor, new()
public void RemoveEntities<T>(uint groupID) where T : IEntityDescriptor, new()
{
throw new NotImplementedException();
//_weakReference.Target.QueueEntitySubmitOperation(
// new EntitySubmitOperation(EntitySubmitOperationType.RemoveGroup, -1, -1, groupID, -1, null, typeof(T)));
}

public void RemoveEntities<T>(ExclusiveGroup.ExclusiveGroupStruct groupID)
where T : IEntityDescriptor, new()
{
throw new NotImplementedException();
//_weakReference.Target.QueueEntitySubmitOperation(
// new EntitySubmitOperation(EntitySubmitOperationType.RemoveGroup, -1, -1, groupID, -1, null, typeof(T)));
}

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

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

public void SwapEntityGroup<T>(int entityID, ExclusiveGroup.ExclusiveGroupStruct fromGroupID,
ExclusiveGroup.ExclusiveGroupStruct toGroupID) where T : IEntityDescriptor, new()
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SwapEntityGroup<T>(uint entityID, ExclusiveGroup.ExclusiveGroupStruct fromGroupID,
ExclusiveGroup.ExclusiveGroupStruct toGroupID)
where T : IEntityDescriptor, new()
{
SwapEntityGroup<T>(new EGID(entityID, fromGroupID), toGroupID);
}

public void SwapEntityGroup<T>(EGID id, ExclusiveGroup.ExclusiveGroupStruct toGroupID)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SwapEntityGroup<T>(EGID fromID, ExclusiveGroup.ExclusiveGroupStruct toGroupID)
where T : IEntityDescriptor, new()
{
SwapEntityGroup<T>(id, new EGID(id.entityID, toGroupID));
SwapEntityGroup<T>(fromID, new EGID(fromID.entityID, (uint)toGroupID));
}
public void SwapEntityGroup<T>(EGID id, ExclusiveGroup.ExclusiveGroupStruct toGroupID
, ExclusiveGroup.ExclusiveGroupStruct mustBeFromGroup) where T : IEntityDescriptor, new()
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SwapEntityGroup<T>(EGID fromID, ExclusiveGroup.ExclusiveGroupStruct toGroupID
, ExclusiveGroup.ExclusiveGroupStruct mustBeFromGroup)
where T : IEntityDescriptor, new()
{
if (id.groupID != mustBeFromGroup)
if (fromID.groupID != mustBeFromGroup)
throw new ECSException("Entity is not coming from the expected group");

SwapEntityGroup<T>(id, toGroupID);
SwapEntityGroup<T>(fromID, toGroupID);
}
public void SwapEntityGroup<T>(EGID id, EGID toID)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SwapEntityGroup<T>(EGID fromID, EGID toID)
where T : IEntityDescriptor, new()
{
_weakReference.Target.QueueEntitySubmitOperation<T>(
new EntitySubmitOperation(EntitySubmitOperationType.Swap,
id.entityID, toID.entityID, id.groupID, toID.groupID,
EntityDescriptorTemplate<T>.descriptor.entitiesToBuild, typeof(T)));
fromID, toID, EntityDescriptorTemplate<T>.descriptor.entitiesToBuild, typeof(T)));
}
public void SwapEntityGroup<T>(EGID id, EGID toID
, ExclusiveGroup.ExclusiveGroupStruct mustBeFromGroup) where T : IEntityDescriptor, new()
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SwapEntityGroup<T>(EGID fromID, EGID toID
, ExclusiveGroup.ExclusiveGroupStruct mustBeFromGroup)
where T : IEntityDescriptor, new()
{
if (id.groupID != mustBeFromGroup)
if (fromID.groupID != mustBeFromGroup)
throw new ECSException("Entity is not coming from the expected group");
SwapEntityGroup<T>(id, toID);
SwapEntityGroup<T>(fromID, toID);
}
}
@@ -106,30 +115,28 @@ namespace Svelto.ECS
#if DEBUG && !PROFILER
entitySubmitOperation.trace = Environment.StackTrace;
#endif
_entitiesOperations.AddRef(ref entitySubmitOperation);
_entitiesOperations.Add((ulong)entitySubmitOperation.fromID, ref entitySubmitOperation);
}

void QueueEntitySubmitOperation<T>(EntitySubmitOperation entitySubmitOperation) where T:IEntityDescriptor
{
#if DEBUG && !PROFILER
#if DEBUG && !PROFILER
entitySubmitOperation.trace = Environment.StackTrace;
var egid = new EGID(entitySubmitOperation.ID, entitySubmitOperation.fromGroupID);
if (_entitiesOperationsDebug.ContainsKey((long)egid) == true)
Console.LogError("Only one entity operation per submission is allowed. id: "
.FastConcat(entitySubmitOperation.ID)
.FastConcat(" groupid: ")
.FastConcat(entitySubmitOperation.fromGroupID)
.FastConcat(" entityType: ")
.FastConcat(typeof(T).Name)
.FastConcat(" submission type ", entitySubmitOperation.type.ToString(),
" previous type: ", _entitiesOperationsDebug[(long)egid].ToString()));
if (_entitiesOperations.TryGetValue((ulong) entitySubmitOperation.fromID, out var entitySubmitedOperation) == true)
{
if (entitySubmitedOperation != entitySubmitOperation)
Console.LogError("Only one entity operation per submission is allowed".FastConcat(" entityViewType: ")
.FastConcat(typeof(T).Name)
.FastConcat(" submission type ", entitySubmitOperation.type.ToString(),
" from ID: ", entitySubmitOperation.fromID.entityID.ToString())
.FastConcat( " previous operation type: ",
_entitiesOperations[(ulong) entitySubmitOperation.fromID].type
.ToString()));
}
else
_entitiesOperationsDebug[(long)egid] = entitySubmitOperation.type;
#endif
_entitiesOperations.AddRef(ref entitySubmitOperation);
_entitiesOperations.Set((ulong)entitySubmitOperation.fromID, ref entitySubmitOperation);
}
#if DEBUG && !PROFILER
readonly Svelto.DataStructures.Experimental.FasterDictionary<long, EntitySubmitOperationType> _entitiesOperationsDebug;
#endif
}
}

+ 65
- 78
Svelto.ECS/EnginesRoot.Submission.cs View File

@@ -10,6 +10,8 @@ namespace Svelto.ECS
{
public partial class EnginesRoot
{
readonly FasterList<EntitySubmitOperation> _transientEntitiesOperations;
void SubmitEntityViews()
{
var profiler = new PlatformProfiler();
@@ -19,11 +21,9 @@ namespace Svelto.ECS
{
using (profiler.Sample("Remove and Swap operations"))
{
#if DEBUG && !PROFILER
_entitiesOperationsDebug.Clear();
#endif
_transientEntitiesOperations.FastClear();
_transientEntitiesOperations.AddRange(_entitiesOperations);
var entitySubmitOperations = _entitiesOperations.GetValuesArray(out var count);
_transientEntitiesOperations.AddRange(entitySubmitOperations, count);
_entitiesOperations.FastClear();

var entitiesOperations = _transientEntitiesOperations.ToArrayFast();
@@ -36,22 +36,19 @@ namespace Svelto.ECS
case EntitySubmitOperationType.Swap:
SwapEntityGroup(entitiesOperations[i].builders,
entitiesOperations[i].entityDescriptor,
new EGID(entitiesOperations[i].ID,
entitiesOperations[i].fromGroupID),
new EGID(entitiesOperations[i].toID,
entitiesOperations[i].toGroupID));
entitiesOperations[i].fromID,
entitiesOperations[i].toID);
break;
case EntitySubmitOperationType.Remove:
MoveEntity(entitiesOperations[i].builders,
new EGID(entitiesOperations[i].ID,
entitiesOperations[i].fromGroupID),
entitiesOperations[i].entityDescriptor, new EGID());
entitiesOperations[i].fromID,
entitiesOperations[i].entityDescriptor, null);
break;
case EntitySubmitOperationType.RemoveGroup:
if (entitiesOperations[i].entityDescriptor == null)
RemoveGroupAndEntitiesFromDB(entitiesOperations[i].fromGroupID);
RemoveGroupAndEntitiesFromDB(entitiesOperations[i].fromID.groupID);
else
RemoveGroupAndEntitiesFromDB(entitiesOperations[i].fromGroupID,
RemoveGroupAndEntitiesFromDB(entitiesOperations[i].fromID.groupID,
entitiesOperations[i].entityDescriptor);

break;
@@ -59,37 +56,27 @@ namespace Svelto.ECS
}
catch (Exception e)
{
#if DEBUG && !PROFILER
var str = "Crash while executing Entity Operation"
.FastConcat(entitiesOperations[i].type.ToString()).FastConcat(" id: ")
.FastConcat(entitiesOperations[i].ID).FastConcat(" to id: ")
.FastConcat(entitiesOperations[i].toID).FastConcat(" from groupid: ")
.FastConcat(entitiesOperations[i].fromGroupID).FastConcat(" to groupid: ")
.FastConcat(entitiesOperations[i].toGroupID);
#if RELAXED_ECS
Console.LogException(str.FastConcat(" ", entitiesOperations[i].trace), e);
.FastConcat(entitiesOperations[i].type.ToString());
#if RELAXED_ECS && !PROFILER
Console.LogException(str.FastConcat(" "
#if DEBUG && !PROFILER
, entitiesOperations[i].trace
#endif
), e);
#else
throw new ECSException(str.FastConcat(" ").FastConcat(entitiesOperations[i].trace), e);
throw new ECSException(str.FastConcat(" ")
#if DEBUG && !PROFILER
.FastConcat(entitiesOperations[i].trace)
#endif
#else
var str = "Entity Operation is ".FastConcat(entitiesOperations[i].type.ToString())
.FastConcat(" id: ")
.FastConcat(entitiesOperations[i].ID)
.FastConcat(" to id: ")
.FastConcat(entitiesOperations[i].toID)
.FastConcat(" from groupid: ")
.FastConcat(entitiesOperations[i].fromGroupID)
.FastConcat(" to groupid: ")
.FastConcat(entitiesOperations[i].toGroupID);

Console.LogException(str, e);
, e);
#endif
}
}
}
}

if (_groupedEntityToAdd.current.Count > 0)
if (_groupedEntityToAdd.currentEntitiesCreatedPerGroup.Count > 0)
{
using (profiler.Sample("Add operations"))
{
@@ -98,18 +85,12 @@ namespace Svelto.ECS

try
{
//Note: if N entity of the same type are added on the same frame the Add callback is called N
//times on the same frame. if the Add callback builds a new entity, that entity will not
//be available in the database until the N callbacks are done solving it could be complicated as
//callback and database update must be interleaved.
AddEntityViewsToTheDBAndSuitableEngines(_groupedEntityToAdd.other, profiler);
//Note: if N entity of the same type are added on the same frame the Add callback is called
//N times on the same frame. if the Add callback builds a new entity, that entity will not
//be available in the database until the N callbacks are done. Solving this could be
//complicated as callback and database update must be interleaved.
AddEntityViewsToTheDBAndSuitableEngines(_groupedEntityToAdd, profiler);
}
#if !DEBUG
catch (Exception e)
{
Console.LogException(e);
}
#endif
finally
{
//other can be cleared now, but let's avoid deleting the dictionary every time
@@ -120,57 +101,63 @@ namespace Svelto.ECS
}
}

void AddEntityViewsToTheDBAndSuitableEngines(
FasterDictionary<int, Dictionary<Type, ITypeSafeDictionary>> groupsOfEntitiesToSubmit,
PlatformProfiler profiler)
void AddEntityViewsToTheDBAndSuitableEngines(DoubleBufferedEntitiesToAdd dbgroupsOfEntitiesToSubmit,
PlatformProfiler profiler)
{
//each group is indexed by entity view type. for each type there is a dictionary indexed by entityID
var groupsOfEntitiesToSubmit = dbgroupsOfEntitiesToSubmit.other;
foreach (var groupOfEntitiesToSubmit in groupsOfEntitiesToSubmit)
{
Dictionary<Type, ITypeSafeDictionary> groupDB;
int groupID = groupOfEntitiesToSubmit.Key;

{
var groupID = groupOfEntitiesToSubmit.Key;
if (dbgroupsOfEntitiesToSubmit.otherEntitiesCreatedPerGroup.ContainsKey(groupID) == false) continue;
//if the group doesn't exist in the current DB let's create it first
if (_groupEntityDB.TryGetValue(groupID, out groupDB) == false)
if (_groupEntityDB.TryGetValue(groupID, out var groupDB) == false)
groupDB = _groupEntityDB[groupID] = new Dictionary<Type, ITypeSafeDictionary>();
//add the entityViews in the group
foreach (var entityViewTypeSafeDictionary in groupOfEntitiesToSubmit.Value)
foreach (var entityViewsToSubmit in groupOfEntitiesToSubmit.Value)
{
ITypeSafeDictionary dbDic;
FasterDictionary<int, ITypeSafeDictionary> groupedGroup = null;
if (groupDB.TryGetValue(entityViewTypeSafeDictionary.Key, out dbDic) == false)
dbDic = groupDB[entityViewTypeSafeDictionary.Key] = entityViewTypeSafeDictionary.Value.Create();

if (_groupsPerEntity.TryGetValue(entityViewTypeSafeDictionary.Key, out groupedGroup) == false)
groupedGroup = _groupsPerEntity[entityViewTypeSafeDictionary.Key] =
new FasterDictionary<int, ITypeSafeDictionary>();

var type = entityViewsToSubmit.Key;
var typeSafeDictionary = entityViewsToSubmit.Value;
if (groupDB.TryGetValue(type, out var dbDic) == false)
dbDic = groupDB[type] = typeSafeDictionary.Create();
//Fill the DB with the entity views generate this frame.
dbDic.FillWithIndexedEntities(entityViewTypeSafeDictionary.Value);
dbDic.AddEntitiesFromDictionary(typeSafeDictionary, groupID);

if (_groupsPerEntity.TryGetValue(type, out var groupedGroup) == false)
groupedGroup = _groupsPerEntity[type] = new FasterDictionary<uint, ITypeSafeDictionary>();
groupedGroup[groupID] = dbDic;
}
}

//then submit everything in the engines, so that the DB is up to date
//with all the entity views and struct created by the entity built
foreach (var groupToSubmit in groupsOfEntitiesToSubmit)
//then submit everything in the engines, so that the DB is up to date with all the entity views and struct
//created by the entity built
using (profiler.Sample("Add entities to engines"))
{
foreach (var entityViewsPerType in groupToSubmit.Value)
foreach (var groupToSubmit in groupsOfEntitiesToSubmit)
{
using (profiler.Sample("Add entities to engines"))
var groupID = groupToSubmit.Key;
var groupDB = _groupEntityDB[groupID];
foreach (var entityViewsPerType in groupToSubmit.Value)
{
entityViewsPerType.Value.AddEntitiesToEngines(_entityEngines, ref profiler);
var realDic = groupDB[entityViewsPerType.Key];
entityViewsPerType.Value.AddEntitiesToEngines(_reactiveEnginesAddRemove, realDic, ref profiler);
}
}
}
}

readonly DoubleBufferedEntitiesToAdd<FasterDictionary<int, Dictionary<Type, ITypeSafeDictionary>>>
_groupedEntityToAdd;

readonly IEntitySubmissionScheduler _scheduler;
readonly FasterList<EntitySubmitOperation> _transientEntitiesOperations;
readonly FasterList<EntitySubmitOperation> _entitiesOperations;
readonly DoubleBufferedEntitiesToAdd _groupedEntityToAdd;
readonly IEntitySubmissionScheduler _scheduler;
readonly FasterDictionary<ulong, EntitySubmitOperation> _entitiesOperations;
//temp
}
}

+ 109
- 163
Svelto.ECS/EntitiesDB.cs View File

@@ -4,7 +4,7 @@

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using Svelto.DataStructures;
using Svelto.DataStructures.Experimental;

@@ -12,289 +12,235 @@ namespace Svelto.ECS.Internal
{
partial class EntitiesDB : IEntitiesDB
{
internal EntitiesDB(FasterDictionary<int, Dictionary<Type, ITypeSafeDictionary>> groupEntityViewsDB,
Dictionary<Type, FasterDictionary<int, ITypeSafeDictionary>> groupedGroups)
internal EntitiesDB(FasterDictionary<uint, Dictionary<Type, ITypeSafeDictionary>> groupEntityViewsDB,
Dictionary<Type, FasterDictionary<uint, ITypeSafeDictionary>> groupsPerEntity, EntitiesStream entityStream)
{
_groupEntityViewsDB = groupEntityViewsDB;
_groupedGroups = groupedGroups;
_groupsPerEntity = groupsPerEntity;
_entityStream = entityStream;
}

public ReadOnlyCollectionStruct<T> QueryEntityViews<T>(int group) where T:class, IEntityStruct
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref T QueryUniqueEntity<T>(ExclusiveGroup.ExclusiveGroupStruct @group) where T : struct, IEntityStruct
{
if (QueryEntitySafeDictionary(group, out TypeSafeDictionary<T> typeSafeDictionary) == false)
return new ReadOnlyCollectionStruct<T>(RetrieveEmptyEntityViewArray<T>(), 0);
var entities = QueryEntities<T>(@group, out var count);

return typeSafeDictionary.Values;
}

public ReadOnlyCollectionStruct<T> QueryEntityViews<T>(ExclusiveGroup.ExclusiveGroupStruct group) where T : class, IEntityStruct
{
return QueryEntityViews<T>((int) group);
}

public T QueryEntityView<T>(int id, ExclusiveGroup.ExclusiveGroupStruct group) where T : class, IEntityStruct
{
return QueryEntityView<T>(new EGID(id, (int) group));
}

public ref T QueryUniqueEntity<T>(int @group) where T : IEntityStruct
{
var entities = QueryEntities<T>(group, out var count);
if (count != 1) throw new ECSException("Unique entities must be unique!".FastConcat(typeof(T).ToString()));
if (count != 1) throw new ECSException("Unique entities must be unique! ".FastConcat(typeof(T).ToString()));
return ref entities[0];
}
public ref T QueryUniqueEntity<T>(ExclusiveGroup.ExclusiveGroupStruct @group) where T : IEntityStruct
{
return ref QueryUniqueEntity<T>((int) @group);
}

public ref T QueryEntity<T>(EGID entityGID) where T : IEntityStruct
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref T QueryEntity<T>(EGID entityGID) where T : struct, IEntityStruct
{
T[] array;
if ((array = QueryEntitiesAndIndexInternal<T>(entityGID, out var index)) != null)
return ref array[index];
throw new EntityNotFoundException(entityGID.entityID, entityGID.groupID, typeof(T));
}
public ref T QueryEntity<T>(int id, ExclusiveGroup.ExclusiveGroupStruct group) where T : IEntityStruct
{
return ref QueryEntity<T>(new EGID(id, group));

throw new EntityNotFoundException(entityGID, typeof(T));
}

public ref T QueryEntity<T>(int id, int group) where T : IEntityStruct
public ref T QueryEntity<T>(uint id, ExclusiveGroup.ExclusiveGroupStruct @group) where T : struct, IEntityStruct
{
return ref QueryEntity<T>(new EGID(id, group));
return ref QueryEntity<T>(new EGID(id, @group));
}

public T[] QueryEntities<T>(int group, out int count) where T : IEntityStruct
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T[] QueryEntities<T>(ExclusiveGroup.ExclusiveGroupStruct groupStruct, out uint count) where T : struct, IEntityStruct
{
uint @group = groupStruct;
count = 0;
if (QueryEntitySafeDictionary(group, out TypeSafeDictionary<T> typeSafeDictionary) == false)
if (QueryEntitySafeDictionary(@group, out TypeSafeDictionary<T> typeSafeDictionary) == false)
return RetrieveEmptyEntityViewArray<T>();

return typeSafeDictionary.GetValuesArray(out count);
}

public T[] QueryEntities<T>(ExclusiveGroup.ExclusiveGroupStruct groupStruct, out int count) where T : IEntityStruct
public EntityCollection<T> QueryEntities<T>(ExclusiveGroup.ExclusiveGroupStruct groupStruct)
where T : struct, IEntityStruct
{
return new EntityCollection<T>(QueryEntities<T>(groupStruct, out var count), count);
}

public EntityCollections<T> QueryEntities<T>(ExclusiveGroup[] groups) where T : struct, IEntityStruct
{
return QueryEntities<T>((int) groupStruct, out count);
return new EntityCollections<T>(this, groups);
}

public (T1[], T2[]) QueryEntities<T1, T2>(int @group, out int count) where T1 : IEntityStruct where T2 : IEntityStruct
public EntityCollections<T1, T2> QueryEntities<T1, T2>(ExclusiveGroup[] groups)
where T1 : struct, IEntityStruct where T2 : struct, IEntityStruct
{
var T1entities = QueryEntities<T1>(group, out var countCheck);
var T2entities = QueryEntities<T2>(group, out count);
if (count != countCheck)
return new EntityCollections<T1, T2>(this, groups);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public (T1[], T2[]) QueryEntities<T1, T2>(ExclusiveGroup.ExclusiveGroupStruct groupStruct, out uint count)
where T1 : struct, IEntityStruct
where T2 : struct, IEntityStruct
{
var T1entities = QueryEntities<T1>(@groupStruct, out var countCheck);
var T2entities = QueryEntities<T2>(@groupStruct, out count);

if (count != countCheck)
throw new ECSException("Entity views count do not match in group. Entity 1: ".
FastConcat(typeof(T1).ToString()).FastConcat(
"Entity 2: ".FastConcat(typeof(T2).ToString())));
FastConcat(typeof(T1).ToString()).FastConcat(
"Entity 2: ".FastConcat(typeof(T2).ToString())));


return (T1entities, T2entities);
}

public (T1[], T2[]) QueryEntities<T1, T2>(ExclusiveGroup.ExclusiveGroupStruct groupStruct, out int count) where T1 : IEntityStruct where T2 : IEntityStruct
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public (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
{
return QueryEntities<T1, T2>((int) groupStruct, out count);
var T1entities = QueryEntities<T1>(@groupStruct, out var countCheck1);
var T2entities = QueryEntities<T2>(@groupStruct, out var countCheck2);
var T3entities = QueryEntities<T3>(@groupStruct, out count);

if (count != countCheck1 || count != countCheck2)
throw new ECSException("Entity views count do not match in group. Entity 1: ".
FastConcat(typeof(T1).ToString()).
FastConcat(" Entity 2: ".FastConcat(typeof(T2).ToString()).
FastConcat(" Entity 3: ".FastConcat(typeof(T3).ToString()))));

return (T1entities, T2entities, T3entities);
}

public EGIDMapper<T> QueryMappedEntities<T>(int groupID) where T : IEntityStruct
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public EGIDMapper<T> QueryMappedEntities<T>(ExclusiveGroup.ExclusiveGroupStruct groupStructId) where T : struct, IEntityStruct
{
TypeSafeDictionary<T> typeSafeDictionary;
if (QueryEntitySafeDictionary(groupID, out typeSafeDictionary) == false)
throw new EntityGroupNotFoundException(groupID, typeof(T));
uint groupId = groupStructId;
if (QueryEntitySafeDictionary(groupId, out TypeSafeDictionary<T> typeSafeDictionary) == false)
throw new EntityGroupNotFoundException(groupId, typeof(T));

EGIDMapper<T> mapper;
mapper.map = typeSafeDictionary;

int count;
typeSafeDictionary.GetValuesArray(out count);
typeSafeDictionary.GetValuesArray(out _);

return mapper;
}

public EGIDMapper<T> QueryMappedEntities<T>(ExclusiveGroup.ExclusiveGroupStruct groupStructId) where T : IEntityStruct
{
return QueryMappedEntities<T>((int) groupStructId);
}

public T[] QueryEntitiesAndIndex<T>(EGID entityGID, out uint index) where T : IEntityStruct
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T[] QueryEntitiesAndIndex<T>(EGID entityGID, out uint index) where T : struct, IEntityStruct
{
T[] array;
if ((array = QueryEntitiesAndIndexInternal<T>(entityGID, out index)) != null)
return array;
throw new EntityNotFoundException(entityGID.entityID, entityGID.groupID, typeof(T));
throw new EntityNotFoundException(entityGID, typeof(T));
}
public bool TryQueryEntitiesAndIndex<T>(EGID entityGid, out uint index, out T[] array) where T : IEntityStruct

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryQueryEntitiesAndIndex<T>(EGID entityGid, out uint index, out T[] array) where T : struct, IEntityStruct
{
if ((array = QueryEntitiesAndIndexInternal<T>(entityGid, out index)) != null)
return true;
return false;
}

public T[] QueryEntitiesAndIndex<T>(int id, ExclusiveGroup.ExclusiveGroupStruct group, out uint index) where T : IEntityStruct
{
return QueryEntitiesAndIndex<T>(new EGID(id, group), out index);
}

public bool TryQueryEntitiesAndIndex<T>(int id, ExclusiveGroup.ExclusiveGroupStruct group, out uint index, out T[] array) where T : IEntityStruct
{
return TryQueryEntitiesAndIndex(new EGID(id, group), out index, out array);
return false;
}

public T[] QueryEntitiesAndIndex<T>(int id, int group, out uint index) where T : IEntityStruct
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T[] QueryEntitiesAndIndex<T>(uint id, ExclusiveGroup.ExclusiveGroupStruct group, out uint index) where T : struct, IEntityStruct
{
return QueryEntitiesAndIndex<T>(new EGID(id, group), out index);
}

public bool TryQueryEntitiesAndIndex<T>(int id, int group, out uint index, out T[] array) where T : IEntityStruct
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryQueryEntitiesAndIndex<T>(uint id, ExclusiveGroup.ExclusiveGroupStruct group, out uint index, out T[] array) where T : struct, IEntityStruct
{
return TryQueryEntitiesAndIndex(new EGID(id, group), out index, out array);
}

public T QueryEntityView<T>(EGID entityGID) where T : class, IEntityStruct
{
T entityView;

if (TryQueryEntityViewInGroupInternal(entityGID, out entityView) == false)
throw new EntityNotFoundException(entityGID.entityID, entityGID.groupID, typeof(T));

return entityView;
}

public bool Exists<T>(EGID entityGID) where T : IEntityStruct
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Exists<T>(EGID entityGID) where T : struct, IEntityStruct
{
TypeSafeDictionary<T> casted;
if (QueryEntitySafeDictionary(entityGID.groupID, out casted) == false) return false;
if (QueryEntitySafeDictionary(entityGID.groupID, out TypeSafeDictionary<T> casted) == false) return false;

return casted != null && casted.ContainsKey(entityGID.entityID);
}

public bool Exists<T>(int id, int groupid) where T : IEntityStruct
{
return Exists<T>(new EGID(id, groupid));
}

//search for the group
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Exists(ExclusiveGroup.ExclusiveGroupStruct gid)
{
return _groupEntityViewsDB.ContainsKey(gid);
}

public bool HasAny<T>(int group) where T : IEntityStruct
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool HasAny<T>(ExclusiveGroup.ExclusiveGroupStruct groupStruct) where T : struct, IEntityStruct
{
int count;
QueryEntities<T>(group, out count);
QueryEntities<T>(groupStruct, out var count);
return count > 0;
}

public bool HasAny<T>(ExclusiveGroup.ExclusiveGroupStruct groupStruct) where T : IEntityStruct
{
return HasAny<T>((int) groupStruct);
}

public int Count<T>(ExclusiveGroup.ExclusiveGroupStruct groupStruct) where T : IEntityStruct
{
int count;
QueryEntities<T>(groupStruct, out count);
return count;
}

public int Count<T>(int groupStruct) where T : IEntityStruct
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public uint Count<T>(ExclusiveGroup.ExclusiveGroupStruct groupStruct) where T : struct, IEntityStruct
{
int count;
QueryEntities<T>(groupStruct, out count);
QueryEntities<T>(groupStruct, out var count);
return count;
}

public bool TryQueryEntityView<T>(EGID entityegid, out T entityView) where T : class, IEntityStruct
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PublishEntityChange<T>(EGID egid) where T : unmanaged, IEntityStruct
{
return TryQueryEntityViewInGroupInternal(entityegid, out entityView);
_entityStream.PublishEntity(ref QueryEntity<T>(egid));
}
public bool TryQueryEntityView<T>(int id, ExclusiveGroup.ExclusiveGroupStruct group, out T entityView) where T : class, IEntityStruct
{
return TryQueryEntityViewInGroupInternal(new EGID(id, (int) group), out entityView);
}
bool TryQueryEntityViewInGroupInternal<T>(EGID entityGID, out T entityView) where T:class, IEntityStruct
{
entityView = null;
TypeSafeDictionary<T> safeDictionary;
if (QueryEntitySafeDictionary(entityGID.groupID, out safeDictionary) == false) return false;

return safeDictionary.TryGetValue(entityGID.entityID, out entityView);
}

T[] QueryEntitiesAndIndexInternal<T>(EGID entityGID, out uint index) where T : IEntityStruct
[MethodImpl(MethodImplOptions.AggressiveInlining)]
T[] QueryEntitiesAndIndexInternal<T>(EGID entityGID, out uint index) where T : struct, IEntityStruct
{
TypeSafeDictionary<T> safeDictionary;
index = 0;
if (QueryEntitySafeDictionary(entityGID.groupID, out safeDictionary) == false)
if (QueryEntitySafeDictionary(entityGID.groupID, out TypeSafeDictionary<T> safeDictionary) == false)
return null;

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

int count;
return safeDictionary.GetValuesArray(out count);
return safeDictionary.GetValuesArray(out _);
}
bool QueryEntitySafeDictionary<T>(int group, out TypeSafeDictionary<T> typeSafeDictionary) where T : IEntityStruct

[MethodImpl(MethodImplOptions.AggressiveInlining)]
bool QueryEntitySafeDictionary<T>(uint group, out TypeSafeDictionary<T> typeSafeDictionary) where T : struct, IEntityStruct
{
Dictionary<Type, ITypeSafeDictionary> entitiesInGroupPerType;
typeSafeDictionary = null;

//search for the group
if (_groupEntityViewsDB.TryGetValue(group, out entitiesInGroupPerType) == false)
//search for the group
if (_groupEntityViewsDB.TryGetValue(group, out var entitiesInGroupPerType) == false)
return false;

//search for the indexed entities in the group
ITypeSafeDictionary safeDictionary;
if (entitiesInGroupPerType.TryGetValue(typeof(T), out safeDictionary) == false)
if (entitiesInGroupPerType.TryGetValue(typeof(T), out var safeDictionary) == false)
return false;

//return the indexes entities if they exist
typeSafeDictionary = (safeDictionary as TypeSafeDictionary<T>);
return true;
}
[Conditional("ENABLE_DEBUG_FUNC")]
static void SafetyChecks<T>(TypeSafeDictionary<T> typeSafeDictionary, int count) where T : IEntityStruct
{
if (typeSafeDictionary.Count != count)
throw new ECSException("Entities cannot be swapped or removed during an iteration");
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
static ReadOnlyCollectionStruct<T> RetrieveEmptyEntityViewList<T>()
{
var arrayFast = FasterList<T>.DefaultList.ToArrayFast();

return new ReadOnlyCollectionStruct<T>(arrayFast, 0);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
static T[] RetrieveEmptyEntityViewArray<T>()
{
return FasterList<T>.DefaultList.ToArrayFast();
}
//grouped set of entity views, this is the standard way to handle entity views entity views are grouped per
//group, then indexable per type, then indexable per EGID. however the TypeSafeDictionary can return an array of
//values directly, that can be iterated over, so that is possible to iterate over all the entity views of
//values directly, that can be iterated over, so that is possible to iterate over all the entity views of
//a specific type inside a specific group.
readonly FasterDictionary<int, Dictionary<Type, ITypeSafeDictionary>> _groupEntityViewsDB;
readonly FasterDictionary<uint, Dictionary<Type, ITypeSafeDictionary>> _groupEntityViewsDB;
//needed to be able to iterate over all the entities of the same type regardless the group
//may change in future
readonly Dictionary<Type, FasterDictionary<int, ITypeSafeDictionary>> _groupedGroups;
readonly Dictionary<Type, FasterDictionary<uint, ITypeSafeDictionary>> _groupsPerEntity;
readonly EntitiesStream _entityStream;
}
}

+ 9
- 29
Svelto.ECS/EntityBuilder.CheckFields.cs View File

@@ -7,41 +7,16 @@ using System.Reflection;

namespace Svelto.ECS
{
public partial class EntityBuilder<T>
public static class EntityBuilderUtilities
{
#if DISABLE_CHECKS
[Conditional("_CHECKS_DISABLED")]
#endif
static void CheckFields(Type type, bool needsReflection, bool isRoot)
public static void CheckFields(Type type, bool needsReflection)
{
if (ENTITY_VIEW_TYPE == ENTITYINFOVIEW_TYPE || type == EGIDType || type == ECLUSIVEGROUPSTRUCTTYPE)
if (type == ENTITY_STRUCT_INFO_VIEW || type == EGIDType || type == ECLUSIVEGROUPSTRUCTTYPE)
return;

{
var methods = type.GetMethods(BindingFlags.Public |
BindingFlags.Instance | BindingFlags.DeclaredOnly);

var properties = type.GetProperties(BindingFlags.Public |
BindingFlags.Instance | BindingFlags.DeclaredOnly);

if (isRoot)
{
if (properties.Length > 1)
ProcessError("Entity views cannot have public methods or properties.", type);
if (methods.Length > properties.Length + 1)
ProcessError("Entity views cannot have public methods or properties.", type);
}
else
{
if (properties.Length > 0)
ProcessError("Entity components fields cannot have public methods or properties.", type);

if (methods.Length > 0)
ProcessError("Entity components fields cannot have public methods or properties.", type);
}
}

if (needsReflection == false)
{
if (type.IsClass)
@@ -53,6 +28,8 @@ namespace Svelto.ECS
{
var field = fields[i];
var fieldFieldType = field.FieldType;
if (fieldFieldType == STRINGTYPE) continue;

SubCheckFields(fieldFieldType);
}
@@ -97,7 +74,7 @@ namespace Svelto.ECS
{
if (fieldFieldType.IsValueType == true && !fieldFieldType.IsEnum && fieldFieldType.IsPrimitive == false)
{
CheckFields(fieldFieldType, false, false);
CheckFields(fieldFieldType, false);
}

return;
@@ -110,6 +87,7 @@ namespace Svelto.ECS
static void ProcessError(string message, Type type)
{
#if !RELAXED_ECS
Type ENTITY_VIEW_TYPE = typeof(Type);
throw new EntityStructException(message, ENTITY_VIEW_TYPE, type);
#endif
}
@@ -119,6 +97,8 @@ namespace Svelto.ECS
static readonly Type DISPATCHONSETTYPE = typeof(DispatchOnSet<>);
static readonly Type DISPATCHONCHANGETYPE = typeof(DispatchOnChange<>);
static readonly Type STRINGTYPE = typeof(String);
static readonly Type ENTITY_VIEW_TYPE = typeof(Type);
static readonly Type ENTITY_STRUCT_INFO_VIEW = typeof(EntityStructInfoView);
}
public class EntityStructException : Exception


+ 25
- 31
Svelto.ECS/EntityBuilder.cs View File

@@ -7,15 +7,15 @@ using Svelto.Utilities;

namespace Svelto.ECS
{
public partial class EntityBuilder<T> : IEntityBuilder where T : IEntityStruct, new()
public class EntityBuilder<T> : IEntityBuilder where T : struct, IEntityStruct
{
public EntityBuilder()
{
_initializer = DEFAULT_IT;

CheckFields(ENTITY_VIEW_TYPE, NEEDS_REFLECTION, true);
EntityBuilderUtilities.CheckFields(ENTITY_VIEW_TYPE, NEEDS_REFLECTION);

if (NEEDS_REFLECTION == true)
if (NEEDS_REFLECTION)
EntityView<T>.InitCache();
}

@@ -26,69 +26,63 @@ namespace Svelto.ECS

var castedDic = dictionary as TypeSafeDictionary<T>;

if (NEEDS_REFLECTION == true)
if (NEEDS_REFLECTION)
{
DBC.ECS.Check.Require(implementors != null, "Implementors not found while building an EntityView");
DBC.ECS.Check.Require(castedDic.ContainsKey(entityID.entityID) == false,
"building an entity with already used entity id! id: ".FastConcat((long)entityID).FastConcat(" ", ENTITY_VIEW_NAME));
"building an entity with already used entity id! id: ".FastConcat((ulong) entityID)
.FastConcat(" ", ENTITY_VIEW_NAME));

T entityView;
EntityView<T>.BuildEntityView(entityID, out entityView);
EntityView<T>.BuildEntityView(out var entityView);

this.FillEntityView(ref entityView, entityViewBlazingFastReflection, implementors, implementorsByType,
this.FillEntityView(ref entityView, entityViewBlazingFastReflection, implementors, implementorsByType,
cachedTypes);
castedDic.Add(entityID.entityID, ref entityView);
}
else
{
_initializer.ID = entityID;
castedDic.Add(entityID.entityID, _initializer);
}
}

ITypeSafeDictionary IEntityBuilder.Preallocate(ref ITypeSafeDictionary dictionary, int size)
ITypeSafeDictionary IEntityBuilder.Preallocate(ref ITypeSafeDictionary dictionary, uint size)
{
return Preallocate(ref dictionary, size);
}

public static ITypeSafeDictionary Preallocate(ref ITypeSafeDictionary dictionary, int size)
static ITypeSafeDictionary Preallocate(ref ITypeSafeDictionary dictionary, uint size)
{
if (dictionary == null)
dictionary = new TypeSafeDictionary<T>(size);
else
dictionary.AddCapacity(size);
dictionary.SetCapacity(size);

return dictionary;
}

public Type GetEntityType()
{
return ENTITY_VIEW_TYPE;
}
public Type GetEntityType() { return ENTITY_VIEW_TYPE; }

#if DEBUG && !PROFILER
readonly Dictionary<Type, ECSTuple<object, int>> implementorsByType = new Dictionary<Type, ECSTuple<object, int>>();
readonly Dictionary<Type, ECSTuple<object, int>> implementorsByType =
new Dictionary<Type, ECSTuple<object, int>>();
#else
readonly Dictionary<Type, object> implementorsByType = new Dictionary<Type, object>();
#endif
//this is used to avoid newing a dictionary every time, but it's used locally only and it's cleared for each use
readonly Dictionary<Type, Type[]> cachedTypes = new Dictionary<Type, Type[]>();

static FasterList<KeyValuePair<Type, ActionCast<T>>> entityViewBlazingFastReflection
{
get { return EntityView<T>.cachedFields; }
}
static readonly Type ENTITY_VIEW_TYPE = typeof(T);
static readonly T DEFAULT_IT = default(T);
static readonly Type ENTITYINFOVIEW_TYPE = typeof(EntityInfoView);
static readonly bool NEEDS_REFLECTION = typeof(IEntityViewStruct).IsAssignableFrom(typeof(T));
static readonly string ENTITY_VIEW_NAME = ENTITY_VIEW_TYPE.ToString();
static FasterList<KeyValuePair<Type, ActionCast<T>>> entityViewBlazingFastReflection =>
EntityView<T>.cachedFields;

internal static readonly Type ENTITY_VIEW_TYPE = typeof(T);
static readonly T DEFAULT_IT = default;
static readonly Type ENTITYINFOVIEW_TYPE = typeof(EntityStructInfoView);
static readonly bool NEEDS_REFLECTION = typeof(IEntityViewStruct).IsAssignableFrom(typeof(T));
static readonly string ENTITY_VIEW_NAME = ENTITY_VIEW_TYPE.ToString();
internal static readonly bool HAS_EGID = typeof(INeedEGID).IsAssignableFrom(ENTITY_VIEW_TYPE);

internal T _initializer;
}
}

+ 8
- 0
Svelto.ECS/EntityBuilder.cs.rej View File

@@ -0,0 +1,8 @@
diff a/Assets/Svelto/Svelto.ECS/EntityBuilder.cs b/Assets/Svelto/Svelto.ECS/EntityBuilder.cs (rejected hunks)
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using DBC.ECS;
using Svelto.DataStructures;
using Svelto.ECS.Hybrid;
using Svelto.ECS.Internal;

+ 195
- 0
Svelto.ECS/EntityCollection.cs View File

@@ -0,0 +1,195 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Svelto.ECS.Internal;

namespace Svelto.ECS
{
public struct EntityCollection<T>
{
public EntityCollection(T[] array, uint count)
{
_array = array;
_count = count;
}

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

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

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

readonly IEntitiesDB _db;
readonly ExclusiveGroup[] _groups;
}
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 EntityGroupsIterator(IEntitiesDB db, ExclusiveGroup[] groups) : this()
{
_db = db;
_groups = groups;
_indexGroup = -1;
_index = -1;
}

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

if (++_index < _count)
{
return true;
}

return false;
}

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

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

T IEnumerator<T>. Current => throw new NotImplementedException();
object IEnumerator.Current => throw new NotImplementedException();
public void Dispose() { }

readonly IEntitiesDB _db;
readonly ExclusiveGroup[] _groups;
T[] _array;
uint _count;
int _index;
int _indexGroup;
}

public struct ValueRef<T1, T2>
{
readonly T1[] array1;
readonly T2[] array2;

readonly uint index;

public ValueRef(T1[] entity1, T2[] entity2, uint i):this()
{
array1 = entity1;
array2 = entity2;
index = i;
}

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 EntityGroupsIterator(IEntitiesDB db, ExclusiveGroup[] groups) : this()
{
_db = db;
_groups = groups;
_indexGroup = -1;
_index = -1;
}

public bool MoveNext()
{
while (_index + 1 >= _count && ++_indexGroup < _groups.Length)
{
_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)
{
return true;
}

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 ValueRef<T1, T2> Current => _value;

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

readonly IEntitiesDB _db;
readonly ExclusiveGroup[] _groups;
uint _count;
int _index;
int _indexGroup;
ValueRef<T1, T2> _value;
}

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

public bool MoveNext() { return ++_index < _count; }
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;
}
}

+ 28
- 31
Svelto.ECS/EntityFactory.cs View File

@@ -1,42 +1,42 @@
using System;
using System.Collections.Generic;
using Svelto.DataStructures.Experimental;

namespace Svelto.ECS.Internal
{
static class EntityFactory
{
internal static Dictionary<Type, ITypeSafeDictionary>
BuildGroupedEntities(EGID egid,
FasterDictionary<int, Dictionary<Type, ITypeSafeDictionary>> groupEntityViewsByType,
IEntityBuilder[] entitiesToBuild,
object[] implementors)
internal static Dictionary<Type, ITypeSafeDictionary> BuildGroupedEntities(EGID egid,
EnginesRoot.DoubleBufferedEntitiesToAdd groupEntitiesToAdd, IEntityBuilder[] entitiesToBuild,
object[] implementors)
{
var @group = FetchEntityGroup(egid.groupID, groupEntityViewsByType);
var @group = FetchEntityGroup(egid.groupID, groupEntitiesToAdd);

BuildEntitiesAndAddToGroup(egid, group, entitiesToBuild, implementors);

return group;
}

static Dictionary<Type, ITypeSafeDictionary> FetchEntityGroup(int groupID,
FasterDictionary<int, Dictionary<Type, ITypeSafeDictionary>> groupEntityViewsByType)
static Dictionary<Type, ITypeSafeDictionary> FetchEntityGroup(uint groupID,
EnginesRoot.DoubleBufferedEntitiesToAdd groupEntityViewsByType)
{
Dictionary<Type, ITypeSafeDictionary> group;

if (groupEntityViewsByType.TryGetValue(groupID, out @group) == false)
if (groupEntityViewsByType.current.TryGetValue(groupID, out Dictionary<Type, ITypeSafeDictionary> @group) ==
false)
{
@group = new Dictionary<Type, ITypeSafeDictionary>();
groupEntityViewsByType.Add(groupID, @group);
groupEntityViewsByType.current.Add(groupID, @group);
}

groupEntityViewsByType.currentEntitiesCreatedPerGroup.TryGetValue(groupID, out var value);
groupEntityViewsByType.currentEntitiesCreatedPerGroup[groupID] = value+1;
return @group;
}

static void BuildEntitiesAndAddToGroup(EGID entityID,
Dictionary<Type, ITypeSafeDictionary> @group,
IEntityBuilder[] entitiesToBuild,
object[] implementors)
static void BuildEntitiesAndAddToGroup(EGID entityID,
Dictionary<Type, ITypeSafeDictionary> @group,
IEntityBuilder[] entitiesToBuild,
object[] implementors)
{
var count = entitiesToBuild.Length;
#if DEBUG && !PROFILER
@@ -44,35 +44,32 @@ namespace Svelto.ECS.Internal
for (var index = 0; index < count; ++index)
{
var entityType = entitiesToBuild[index].GetEntityType();
if (types.Contains(entityType))
var entityViewType = entitiesToBuild[index].GetEntityType();
if (types.Contains(entityViewType))
{
throw new ECSException("EntityBuilders must be unique inside an EntityDescriptor");
}
types.Add(entityType);
types.Add(entityViewType);
}
#endif

#endif
for (var index = 0; index < count; ++index)
{
var entityViewBuilder = entitiesToBuild[index];
var entityViewType = entityViewBuilder.GetEntityType();
var entityViewType = entityViewBuilder.GetEntityType();

BuildEntity(entityID, @group, entityViewType, entityViewBuilder, implementors);
}
}

static void BuildEntity(EGID entityID, Dictionary<Type, ITypeSafeDictionary> @group,
Type entityViewType, IEntityBuilder entityBuilder, object[] implementors)
static void BuildEntity(EGID entityID, Dictionary<Type, ITypeSafeDictionary> @group, Type entityViewType,
IEntityBuilder entityBuilder, object[] implementors)
{
ITypeSafeDictionary safeDictionary;

var entityViewsPoolWillBeCreated = @group.TryGetValue(entityViewType, out safeDictionary) == false;
var entityViewsPoolWillBeCreated = @group.TryGetValue(entityViewType, out var safeDictionary) == false;

//passing the undefined entityViewsByType inside the entityViewBuilder will allow
//it to be created with the correct type and casted back to the undefined list.
//that's how the list will be eventually of the target type.
//passing the undefined entityViewsByType inside the entityViewBuilder will allow it to be created with the
//correct type and casted back to the undefined list. that's how the list will be eventually of the target
//type.
entityBuilder.BuildEntityAndAddToList(ref safeDictionary, entityID, implementors);

if (entityViewsPoolWillBeCreated)


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

@@ -4,7 +4,7 @@ namespace Svelto.ECS.Internal
{
class EntityGroupNotFoundException : Exception
{
public EntityGroupNotFoundException(int groupId, Type type)
public EntityGroupNotFoundException(uint groupId, Type type)
: base("entity group not found ".FastConcat(type.ToString()))
{
}


+ 11
- 0
Svelto.ECS/EntityHierarchyStruct.cs View File

@@ -0,0 +1,11 @@
namespace Svelto.ECS
{
public struct EntityHierarchyStruct: IEntityStruct, INeedEGID
{
public readonly ExclusiveGroup.ExclusiveGroupStruct parentGroup;
public EntityHierarchyStruct(ExclusiveGroup @group): this() { parentGroup = group; }
public EGID ID { get; set; }
}
}

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

@@ -2,7 +2,7 @@ using System;

namespace Svelto.ECS
{
public struct EntityInfoView : IEntityStruct
public struct EntityStructInfoView: IEntityStruct, INeedEGID
{
public EGID ID { get; set; }
public Type type { get; set; }


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

@@ -4,7 +4,7 @@ namespace Svelto.ECS
{
public class EntityNotFoundException : Exception
{
public EntityNotFoundException(int entityGidEntityId, int entityGidGroupId, Type type)
public EntityNotFoundException(EGID entityGidEntityId, Type type)
: base("entity not found ".FastConcat(type.ToString()))
{}
}

+ 41
- 38
Svelto.ECS/EntityStream.cs View File

@@ -1,16 +1,10 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using Svelto.DataStructures;

namespace Svelto.ECS
{
public interface IEntitiesStream
{
Consumer<T> GenerateConsumer<T>(int capacity) where T : unmanaged, IEntityStruct;
void PublishEntity<T>(EGID id) where T : unmanaged, IEntityStruct;
}

/// <summary>
/// Do not use this class in place of a normal polling.
/// I eventually realised than in ECS no form of communication other than polling entity components can exist.
@@ -22,31 +16,25 @@ namespace Svelto.ECS
/// one only
/// - you want to communicate between EnginesRoots
/// </summary>
class EntitiesStream : IEntitiesStream
class EntitiesStream
{
public EntitiesStream(IEntitiesDB entitiesDb)
{
_entitiesDB = entitiesDb;
}

public Consumer<T> GenerateConsumer<T>(int capacity) where T : unmanaged, IEntityStruct
internal Consumer<T> GenerateConsumer<T>(string name, int capacity) where T : unmanaged, IEntityStruct
{
if (_streams.ContainsKey(typeof(T)) == false) _streams[typeof(T)] = new EntityStream<T>();
return (_streams[typeof(T)] as EntityStream<T>).GenerateConsumer(capacity);
return (_streams[typeof(T)] as EntityStream<T>).GenerateConsumer(name, capacity);
}

public void PublishEntity<T>(EGID id) where T : unmanaged, IEntityStruct
internal void PublishEntity<T>(ref T entity) where T : unmanaged, IEntityStruct
{
if (_streams.TryGetValue(typeof(T), out var typeSafeStream))
(typeSafeStream as EntityStream<T>).PublishEntity(ref _entitiesDB.QueryEntity<T>(id));
(typeSafeStream as EntityStream<T>).PublishEntity(ref entity);
else
Console.LogWarning("No Consumers are waiting for this entity to change "
.FastConcat(typeof(T).ToString()));
}

readonly Dictionary<Type, ITypeSafeStream> _streams = new Dictionary<Type, ITypeSafeStream>();
readonly IEntitiesDB _entitiesDB;
readonly ConcurrentDictionary<Type, ITypeSafeStream> _streams = new ConcurrentDictionary<Type, ITypeSafeStream>();
}

interface ITypeSafeStream
@@ -60,46 +48,61 @@ namespace Svelto.ECS
_buffers[i].Enqueue(ref entity);
}

public Consumer<T> GenerateConsumer(int capacity)
public Consumer<T> GenerateConsumer(string name, int capacity)
{
var consumer = new Consumer<T>(capacity);
var consumer = new Consumer<T>(name, capacity, this);
_buffers.Add(consumer);
return consumer;
}
public void RemoveConsumer(Consumer<T> consumer)
{
_buffers.UnorderedRemove(consumer);
}

readonly FasterList<Consumer<T>> _buffers = new FasterList<Consumer<T>>();
readonly FasterListThreadSafe<Consumer<T>> _buffers = new FasterListThreadSafe<Consumer<T>>();
}

public class Consumer<T> where T:unmanaged, IEntityStruct
public struct Consumer<T>: IDisposable where T:unmanaged, IEntityStruct
{
public Consumer(int capacity)
internal Consumer(string name, int capacity, EntityStream<T> stream)
{
_ringBuffer = new RingBuffer<T>(capacity);
_capacity = capacity;
_name = name;
_stream = stream;
}

public void Enqueue(ref T entity)
internal void Enqueue(ref T entity)
{
if (_ringBuffer.Count >= _capacity)
throw new Exception("EntityStream capacity has been saturated");
_ringBuffer.Enqueue(ref entity);
_ringBuffer.Enqueue(ref entity, _name);
}

/// <summary>
/// this can be better, I probably would need to get the group regardless if it supports EGID or not
/// </summary>
/// <param name="group"></param>
/// <param name="entity"></param>
/// <returns></returns>
public bool TryDequeue(ExclusiveGroup group, out T entity)
{
if (_ringBuffer.TryDequeue(out entity) == true)
return entity.ID.groupID == @group;
if (_ringBuffer.TryDequeue(out entity, _name) == true)
{
if (EntityBuilder<T>.HAS_EGID)
return (entity as INeedEGID).ID.groupID == @group;

return true;
}

return false;
}
public bool TryDequeue(out T entity) { return _ringBuffer.TryDequeue(out entity); }

public bool TryDequeue(out T entity) { return _ringBuffer.TryDequeue(out entity, _name); }
public void Flush() { _ringBuffer.Reset(); }
public void Dispose() { _stream.RemoveConsumer(this); }
readonly RingBuffer<T> _ringBuffer;
readonly int _capacity;
readonly RingBuffer<T> _ringBuffer;
readonly EntityStream<T> _stream;
readonly string _name;
}
}

+ 18
- 13
Svelto.ECS/EntityStructInitializer.cs View File

@@ -6,26 +6,31 @@ namespace Svelto.ECS
{
public struct EntityStructInitializer
{
public EntityStructInitializer(EGID id, Dictionary<Type, ITypeSafeDictionary> current)
public EntityStructInitializer(EGID id, Dictionary<Type, ITypeSafeDictionary> @group)
{
_current = current;
_id = id;
_group = @group;
ID = id;
}

public void Init<T>(T initializer) where T: struct, IEntityStruct
{
DBC.ECS.Check.Require(_current.ContainsKey(typeof(T) )== true,
"Entity to initialise not generated by the EntiyDescriptor");
var typeSafeDictionary = (TypeSafeDictionary<T>) _current[typeof(T)];
if (_group.TryGetValue(EntityBuilder<T>.ENTITY_VIEW_TYPE, out var typeSafeDictionary) == true)
{
var dictionary = typeSafeDictionary as TypeSafeDictionary<T>;

initializer.ID = _id;
if (EntityBuilder<T>.HAS_EGID)
{
var needEgid = ((INeedEGID) initializer);
needEgid.ID = ID;
initializer = (T) needEgid;
}

int count;
typeSafeDictionary.GetValuesArray(out count)[typeSafeDictionary.FindElementIndex(_id.entityID)] = initializer;
if (dictionary.TryFindElementIndex(ID.entityID, out var findElementIndex))
dictionary.GetValuesArray(out _)[findElementIndex] = initializer;
}
}

readonly Dictionary<Type, ITypeSafeDictionary> _current;
readonly EGID _id;
readonly EGID ID;
readonly Dictionary<Type, ITypeSafeDictionary> _group;
}
}

+ 27
- 13
Svelto.ECS/EntitySubmitOperation.cs View File

@@ -2,41 +2,55 @@

namespace Svelto.ECS
{
#pragma warning disable 660,661
struct EntitySubmitOperation
#pragma warning restore 660,661
: IEquatable<EntitySubmitOperation>
{
public readonly EntitySubmitOperationType type;
public readonly IEntityBuilder[] builders;
public readonly int ID;
public readonly int toID;
public readonly int toGroupID;
public readonly int fromGroupID;
public readonly EGID fromID;
public readonly EGID toID;
public readonly Type entityDescriptor;
#if DEBUG && !PROFILER
public string trace;
#endif

public EntitySubmitOperation(
EntitySubmitOperationType operation, int entityId, int toId, int fromGroupId, int toGroupId,
IEntityBuilder[] builders, Type entityDescriptor)
public EntitySubmitOperation(EntitySubmitOperationType operation, EGID from, EGID to,
IEntityBuilder[] builders = null,
Type entityDescriptor = null)
{
type = operation;
type = operation;
this.builders = builders;
ID = entityId;
toID = toId;
fromID = from;
toID = to;

toGroupID = toGroupId;
fromGroupID = fromGroupId;
this.entityDescriptor = entityDescriptor;
#if DEBUG && !PROFILER
trace = string.Empty;
#endif
}
public static bool operator ==(EntitySubmitOperation obj1, EntitySubmitOperation obj2)
{
return obj1.Equals(obj2);
}
public static bool operator !=(EntitySubmitOperation obj1, EntitySubmitOperation obj2)
{
return obj1.Equals(obj2) == false;
}

public bool Equals(EntitySubmitOperation other)
{
return type == other.type && fromID == other.fromID && toID == other.toID;
}
}

enum EntitySubmitOperationType
{
Swap,
Remove,
RemoveGroup,
RemoveGroup
}
}

+ 3
- 3
Svelto.ECS/EntityView.cs View File

@@ -6,7 +6,7 @@ using Svelto.Utilities;

namespace Svelto.ECS
{
static class EntityView<T> where T: IEntityStruct, new()
static class EntityView<T> where T: struct, IEntityStruct
{
internal static readonly FasterList<KeyValuePair<Type, ActionCast<T>>> cachedFields;

@@ -32,9 +32,9 @@ namespace Svelto.ECS
internal static void InitCache()
{}
internal static void BuildEntityView(EGID ID, out T entityView)
internal static void BuildEntityView(out T entityView)
{
entityView = new T { ID = ID };
entityView = new T {};
}
}
}

+ 3
- 8
Svelto.ECS/EntityViewUtility.cs View File

@@ -38,12 +38,10 @@ namespace Svelto.ECS
, Dictionary<Type, Type[]> cachedTypes
)
{
int count;

//efficient way to collect the fields of every EntityViewType
var setters =
FasterList<KeyValuePair<Type, ActionCast<T>>>
.NoVirt.ToArrayFast(entityViewBlazingFastReflection, out count);
.NoVirt.ToArrayFast(entityViewBlazingFastReflection, out var count);

for (var index = 0; index < implementors.Length; index++)
{
@@ -53,17 +51,14 @@ namespace Svelto.ECS
{
var type = implementor.GetType();

Type[] interfaces;
if (cachedTypes.TryGetValue(type, out interfaces) == false)
if (cachedTypes.TryGetValue(type, out var interfaces) == false)
interfaces = cachedTypes[type] = type.GetInterfacesEx();

for (var iindex = 0; iindex < interfaces.Length; iindex++)
{
var componentType = interfaces[iindex];
#if DEBUG && !PROFILER
ECSTuple<object, int> implementorData;

if (implementorsByType.TryGetValue(componentType, out implementorData))
if (implementorsByType.TryGetValue(componentType, out var implementorData))
{
implementorData.numberOfImplementations++;
implementorsByType[componentType] = implementorData;


+ 9
- 9
Svelto.ECS/ExclusiveGroup.cs View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
#pragma warning disable 660,661

@@ -41,12 +41,12 @@ namespace Svelto.ECS
return group._group;
}
public static explicit operator int(ExclusiveGroup group)
public static explicit operator uint(ExclusiveGroup group)
{
return group._group;
}

public static ExclusiveGroupStruct operator+(ExclusiveGroup a, int b)
public static ExclusiveGroupStruct operator+(ExclusiveGroup a, uint b)
{
return a._group + b;
}
@@ -91,7 +91,7 @@ namespace Svelto.ECS
{
ExclusiveGroupStruct groupStruct;

groupStruct._id = (int) _globalId;
groupStruct._id = _globalId;
DBC.ECS.Check.Require(_globalId + 1 < ushort.MaxValue, "too many exclusive groups created");
_globalId++;

@@ -103,22 +103,22 @@ namespace Svelto.ECS
/// </summary>
internal ExclusiveGroupStruct(ushort range)
{
_id = (int) _globalId;
_id = _globalId;
DBC.ECS.Check.Require(_globalId + range < ushort.MaxValue, "too many exclusive groups created");
_globalId += range;
}
internal ExclusiveGroupStruct(int groupID)
internal ExclusiveGroupStruct(uint groupID)
{
_id = groupID;
}

public static implicit operator int(ExclusiveGroupStruct groupStruct)
public static implicit operator uint(ExclusiveGroupStruct groupStruct)
{
return groupStruct._id;
}
public static ExclusiveGroupStruct operator+(ExclusiveGroupStruct a, int b)
public static ExclusiveGroupStruct operator+(ExclusiveGroupStruct a, uint b)
{
var group = new ExclusiveGroupStruct();

@@ -127,7 +127,7 @@ namespace Svelto.ECS
return group;
}

int _id;
uint _id;
static uint _globalId;
}



+ 19
- 136
Svelto.ECS/ExecuteOnEntitiesDB.cs View File

@@ -1,161 +1,44 @@
using System;

namespace Svelto.ECS.Internal
{
partial class EntitiesDB
{
public void ExecuteOnEntity<T>(int id,
ExclusiveGroup.ExclusiveGroupStruct groupid,
EntityAction<T> action) where T : IEntityStruct
{
ExecuteOnEntity(id, (int)groupid, action);
}

public void ExecuteOnEntity<T, W>(EGID entityGID, ref W value, EntityAction<T, W> action) where T: IEntityStruct
{
TypeSafeDictionary<T> casted;
if (QueryEntitySafeDictionary(entityGID.groupID, out casted))
{
if (casted != null)
if (casted.ExecuteOnEntityView(entityGID.entityID, ref value, action))
return;
}

throw new EntityNotFoundException(entityGID.entityID, entityGID.groupID, typeof(T));
}

public void ExecuteOnEntity<T>(EGID entityGID, EntityAction<T> action) where T : IEntityStruct
{
TypeSafeDictionary<T> casted;
if (QueryEntitySafeDictionary(entityGID.groupID, out casted))
{
if (casted != null)
if (casted.ExecuteOnEntityView(entityGID.entityID, action))
return;
}

throw new EntityNotFoundException(entityGID.entityID, entityGID.groupID, typeof(T));
}

public void ExecuteOnEntity<T>(int id, int groupid, EntityAction<T> action) where T : IEntityStruct
{
ExecuteOnEntity(new EGID(id, groupid), action);
}

public void ExecuteOnEntity<T, W>(int id, int groupid, ref W value, EntityAction<T, W> action)
where T : IEntityStruct
{
ExecuteOnEntity(new EGID(id, groupid), ref value, action);
}

public void ExecuteOnEntity<T, W>(int id,
ExclusiveGroup.ExclusiveGroupStruct groupid,
ref W value,
EntityAction<T, W> action) where T : IEntityStruct
{
ExecuteOnEntity(id, (int)groupid, ref value, action);
}

//----------------------------------------------------------------------------------------------------------

public void ExecuteOnEntities<T>(int groupID, EntitiesAction<T> action) where T : IEntityStruct
{
if (QueryEntitySafeDictionary(groupID, out TypeSafeDictionary<T> typeSafeDictionary) == false) return;

var entities = typeSafeDictionary.GetValuesArray(out var count);

for (var i = 0; i < count; i++)
action(ref entities[i], new EntityActionData(this, i));

SafetyChecks(typeSafeDictionary, count);
}

public void ExecuteOnEntities<T>(ExclusiveGroup.ExclusiveGroupStruct groupStructId,
EntitiesAction<T> action) where T : IEntityStruct
{
ExecuteOnEntities((int)groupStructId, action);
}

public void ExecuteOnEntities<T, W>(int groupID, ref W value, EntitiesAction<T, W> action) where T:IEntityStruct
{
if (QueryEntitySafeDictionary(groupID, out TypeSafeDictionary<T> typeSafeDictionary) == false) return;

var entities = typeSafeDictionary.GetValuesArray(out var count);

for (var i = 0; i < count; i++)
action(ref entities[i], ref value, new EntityActionData(this, i));

SafetyChecks(typeSafeDictionary, count);
}

public void ExecuteOnEntities<T, W>(ExclusiveGroup.ExclusiveGroupStruct groupStructId,
ref W value, EntitiesAction<T, W> action) where T : IEntityStruct
{
ExecuteOnEntities((int)groupStructId, ref value, action);
}

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

if (_groupedGroups.TryGetValue(type, out var dic))
if (_groupsPerEntity.TryGetValue(type, out var dic))
{
var typeSafeDictionaries = dic.GetValuesArray(out var count);

for (int j = 0; j < count; j++)
foreach (var pair in dic)
{
var typeSafeDictionary = typeSafeDictionaries[j];
var casted = typeSafeDictionary as TypeSafeDictionary<T>;
var entities =
(pair.Value as TypeSafeDictionary<T>).GetValuesArray(out var innerCount);

var entities = casted.GetValuesArray(out var innerCount);

for (int i = 0; i < innerCount; i++)
action(ref entities[i], this);

SafetyChecks(casted, innerCount);
if (innerCount > 0)
action(entities, new ExclusiveGroup.ExclusiveGroupStruct(pair.Key), innerCount, this);
}
}
}

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

if (_groupedGroups.TryGetValue(type, out var dic))
if (_groupsPerEntity.TryGetValue(type, out var dic))
{
var typeSafeDictionaries = dic.GetValuesArray(out var count);

for (int j = 0; j < count; j++)
foreach (var pair in dic)
{
var typeSafeDictionary = typeSafeDictionaries[j];
var casted = typeSafeDictionary as TypeSafeDictionary<T>;

var entities = casted.GetValuesArray(out var innerCount);
var entities =
(pair.Value as TypeSafeDictionary<T>).GetValuesArray(out var innerCount);

for (int i = 0; i < innerCount; i++)
action(ref entities[i], ref value, this);

SafetyChecks(casted, innerCount);
if (innerCount > 0)
action(entities, new ExclusiveGroup.ExclusiveGroupStruct(pair.Key), innerCount, this, value);
}
}
}

public void ExecuteOnAllEntities<T>(ExclusiveGroup[] groups, EntitiesAction<T> action) where T : IEntityStruct
{
foreach (var group in groups)
{
ExecuteOnEntities(group, action);
}
}

public void ExecuteOnAllEntities<T, W>(ExclusiveGroup[] groups,
ref W value,
EntitiesAction<T, W> action) where T : IEntityStruct
{
foreach (var group in groups)
{
ExecuteOnEntities(group, ref value, action);
}
}
}
}

+ 6
- 5
Svelto.ECS/Extensions/Unity/GenericEntityDescriptorHolder.cs View File

@@ -3,7 +3,7 @@ using UnityEngine;

namespace Svelto.ECS.Unity
{
public class GenericEntityDescriptorHolder<T>:
public abstract class GenericEntityDescriptorHolder<T>:
MonoBehaviour , IEntityDescriptorHolder
where T: IEntityDescriptor, new()
{
@@ -13,11 +13,12 @@ namespace Svelto.ECS.Unity
}

public string groupName => _groupName;
public ushort id => _id;

[SerializeField]
#pragma warning disable 649
string _groupName;
#pragma warning restore 649
#pragma warning disable 649
[SerializeField] string _groupName;
[SerializeField] ushort _id = 0;
#pragma warning restore 649
}
}
#endif

+ 0
- 38
Svelto.ECS/Extensions/Unity/SveltoEntityFactoryForUnity.cs View File

@@ -1,38 +0,0 @@
#if UNITY_5 || UNITY_5_3_OR_NEWER
using UnityEngine;

namespace Svelto.ECS.Unity
{
public static class SveltoEntityFactoryForUnity
{
public static T Create<T>(EGID ID, Transform contextHolder,
IEntityFactory factory) where T : MonoBehaviour, IEntityDescriptorHolder
{
var holder = contextHolder.GetComponentInChildren<T>(true);
var implementors = holder.GetComponents<IImplementor>();

factory.BuildEntity(ID, holder.GetDescriptor(), implementors);

return holder;
}
public static void CreateAll<T>(ExclusiveGroup group, Transform contextHolder,
IEntityFactory factory) where T : MonoBehaviour, IEntityDescriptorHolder
{
var holders = contextHolder.GetComponentsInChildren<T>(true);

foreach (var holder in holders)
{
var implementors = holder.GetComponents<IImplementor>();

ExclusiveGroup.ExclusiveGroupStruct realGroup = group;

if (string.IsNullOrEmpty( holder.groupName) == false)
realGroup = ExclusiveGroup.Search(holder.groupName);

factory.BuildEntity(holder.GetInstanceID(), realGroup, holder.GetDescriptor(), implementors);
}
}
}
}
#endif

+ 72
- 0
Svelto.ECS/Extensions/Unity/SveltoGUIHelper.cs View File

@@ -0,0 +1,72 @@
#if UNITY_5 || UNITY_5_3_OR_NEWER
using UnityEngine;

namespace Svelto.ECS.Unity
{
public static class SveltoGUIHelper
{
public static T CreateFromPrefab<T>(uint startIndex, Transform contextHolder, IEntityFactory factory, ExclusiveGroup group) where T : MonoBehaviour, IEntityDescriptorHolder
{
var holder = Create<T>(new EGID(startIndex++, group), contextHolder, factory);
var childs = contextHolder.GetComponentsInChildren<IEntityDescriptorHolder>(true);
foreach (var child in childs)
{
if (child.GetType() != typeof(T))
{
var childImplementors = (child as MonoBehaviour).GetComponents<IImplementor>();
InternalBuildAll(startIndex, child, factory, group, childImplementors);
}
}
return holder;
}
public static T Create<T>(EGID ID, Transform contextHolder,
IEntityFactory factory) where T : MonoBehaviour, IEntityDescriptorHolder
{
var holder = contextHolder.GetComponentInChildren<T>(true);
var implementors = holder.GetComponents<IImplementor>();

factory.BuildEntity(ID, holder.GetDescriptor(), implementors);

return holder;
}
public static uint CreateAll<T>(uint startIndex, ExclusiveGroup group, Transform contextHolder,
IEntityFactory factory) where T : MonoBehaviour, IEntityDescriptorHolder
{
var holders = contextHolder.GetComponentsInChildren<T>(true);

foreach (var holder in holders)
{
var implementors = holder.GetComponents<IImplementor>();

InternalBuildAll(startIndex, holder, factory, group, implementors);
}

return startIndex;
}
static void InternalBuildAll(uint startIndex, IEntityDescriptorHolder descriptorHolder, IEntityFactory factory, ExclusiveGroup group, IImplementor[] implementors)
{
ExclusiveGroup.ExclusiveGroupStruct realGroup = group;
if (string.IsNullOrEmpty(descriptorHolder.groupName) == false)
realGroup = ExclusiveGroup.Search(descriptorHolder.groupName);

EGID egid;
var holderId = descriptorHolder.id;
if (holderId == 0)
egid = new EGID(startIndex++, realGroup);
else
egid = new EGID(holderId, realGroup);

var init = factory.BuildEntity(egid, descriptorHolder.GetDescriptor(), implementors);
init.Init(new EntityHierarchyStruct(group));
}
}
}
#endif

+ 4
- 1
Svelto.ECS/Extensions/Unity/UnityEntitySubmissionScheduler.cs View File

@@ -30,13 +30,15 @@ namespace Svelto.ECS.Schedulers.Unity
public WeakAction onTick;
}
public UnityEntitySubmissionScheduler(string name = "ECSScheduler") { _name = name; }
public WeakAction onTick
{
set
{
if (_scheduler == null)
{
GameObject go = new GameObject("ECSScheduler");
GameObject go = new GameObject(_name);

_scheduler = go.AddComponent<Scheduler>();
}
@@ -45,6 +47,7 @@ namespace Svelto.ECS.Schedulers.Unity
}

Scheduler _scheduler;
string _name;
}
}
#endif

+ 33
- 62
Svelto.ECS/GenericEntityDescriptor.cs View File

@@ -1,40 +1,31 @@
namespace Svelto.ECS
{
public abstract class GenericEntityDescriptor<T>:IEntityDescriptor where T : IEntityStruct, new()
public abstract class GenericEntityDescriptor<T> : IEntityDescriptor where T : struct, IEntityStruct
{
static GenericEntityDescriptor()
{
_entityBuilders = new IEntityBuilder[] { new EntityBuilder<T>() };
}
public IEntityBuilder[] entitiesToBuild
{
get { return _entityBuilders; }
}

static readonly IEntityBuilder[] _entityBuilders;
static GenericEntityDescriptor() { _entityBuilders = new IEntityBuilder[] {new EntityBuilder<T>()}; }

public IEntityBuilder[] entitiesToBuild => _entityBuilders;
}

public abstract class GenericEntityDescriptor<T, U> : IEntityDescriptor where T : IEntityStruct, new()
where U : IEntityStruct, new()
public abstract class GenericEntityDescriptor<T, U> : IEntityDescriptor
where T : struct, IEntityStruct where U : struct, IEntityStruct
{
static readonly IEntityBuilder[] _entityBuilders;

static GenericEntityDescriptor()
{
_entityBuilders = new IEntityBuilder[] {new EntityBuilder<T>(), new EntityBuilder<U>()};
}

public IEntityBuilder[] entitiesToBuild
{
get { return _entityBuilders; }
}

static readonly IEntityBuilder[] _entityBuilders;
public IEntityBuilder[] entitiesToBuild => _entityBuilders;
}

public abstract class GenericEntityDescriptor<T, U, V> : IEntityDescriptor where T : IEntityStruct, new()
where U : IEntityStruct, new()
where V : IEntityStruct, new()
public abstract class GenericEntityDescriptor<T, U, V> : IEntityDescriptor
where T : struct, IEntityStruct where U : struct, IEntityStruct where V : struct, IEntityStruct
{
static readonly IEntityBuilder[] _entityBuilders;

static GenericEntityDescriptor()
{
_entityBuilders = new IEntityBuilder[]
@@ -45,19 +36,15 @@
};
}

public IEntityBuilder[] entitiesToBuild
{
get { return _entityBuilders; }
}

static readonly IEntityBuilder[] _entityBuilders;
public IEntityBuilder[] entitiesToBuild => _entityBuilders;
}

public abstract class GenericEntityDescriptor<T, U, V, W> : IEntityDescriptor where T : IEntityStruct, new()
where U : IEntityStruct, new()
where V : IEntityStruct, new()
where W : IEntityStruct, new()
public abstract class GenericEntityDescriptor<T, U, V, W> : IEntityDescriptor
where T : struct, IEntityStruct where U : struct, IEntityStruct where V : struct, IEntityStruct
where W : struct, IEntityStruct
{
static readonly IEntityBuilder[] _entityBuilders;

static GenericEntityDescriptor()
{
_entityBuilders = new IEntityBuilder[]
@@ -69,20 +56,15 @@
};
}

public IEntityBuilder[] entitiesToBuild
{
get { return _entityBuilders; }
}

static readonly IEntityBuilder[] _entityBuilders;
public IEntityBuilder[] entitiesToBuild => _entityBuilders;
}

public abstract class GenericEntityDescriptor<T, U, V, W, X> : IEntityDescriptor where T : IEntityStruct, new()
where U : IEntityStruct, new()
where V : IEntityStruct, new()
where W : IEntityStruct, new()
where X : IEntityStruct, new()
public abstract class GenericEntityDescriptor<T, U, V, W, X> : IEntityDescriptor
where T : struct, IEntityStruct where U : struct, IEntityStruct where V : struct, IEntityStruct
where W : struct, IEntityStruct where X : struct, IEntityStruct
{
static readonly IEntityBuilder[] _entityBuilders;

static GenericEntityDescriptor()
{
_entityBuilders = new IEntityBuilder[]
@@ -95,21 +77,15 @@
};
}

public IEntityBuilder[] entitiesToBuild
{
get { return _entityBuilders; }
}

static readonly IEntityBuilder[] _entityBuilders;
public IEntityBuilder[] entitiesToBuild => _entityBuilders;
}

public abstract class GenericEntityDescriptor<T, U, V, W, X, Y> : IEntityDescriptor where T : IEntityStruct, new()
where U : IEntityStruct, new()
where V : IEntityStruct, new()
where W : IEntityStruct, new()
where X : IEntityStruct, new()
where Y : IEntityStruct, new()
public abstract class GenericEntityDescriptor<T, U, V, W, X, Y> : IEntityDescriptor
where T : struct, IEntityStruct where U : struct, IEntityStruct where V : struct, IEntityStruct
where W : struct, IEntityStruct where X : struct, IEntityStruct where Y : struct, IEntityStruct
{
static readonly IEntityBuilder[] _entityBuilders;

static GenericEntityDescriptor()
{
_entityBuilders = new IEntityBuilder[]
@@ -123,11 +99,6 @@
};
}

public IEntityBuilder[] entitiesToBuild
{
get { return _entityBuilders; }
}

static readonly IEntityBuilder[] _entityBuilders;
public IEntityBuilder[] entitiesToBuild => _entityBuilders;
}
}
}

+ 22
- 0
Svelto.ECS/GenericentityStreamConsumerFactory.cs View File

@@ -0,0 +1,22 @@
namespace Svelto.ECS
{
class GenericentityStreamConsumerFactory : IEntityStreamConsumerFactory
{
public GenericentityStreamConsumerFactory(DataStructures.WeakReference<EnginesRoot> weakReference)
{
_enginesRoot = weakReference;
}

public Consumer<T> GenerateConsumer<T>(string name, int capacity) where T : unmanaged, IEntityStruct
{
return _enginesRoot.Target.GenerateConsumer<T>(name, capacity);
}

readonly DataStructures.WeakReference<EnginesRoot> _enginesRoot;
}
public interface IEntityStreamConsumerFactory
{
Consumer<T> GenerateConsumer<T>(string name, int capacity) where T : unmanaged, IEntityStruct;
}
}

+ 6
- 0
Svelto.ECS/Hybrid/IEntityViewStruct.cs View File

@@ -0,0 +1,6 @@
namespace Svelto.ECS.Hybrid
{
public interface IEntityViewStruct:IEntityStruct, INeedEGID
{}
}


Svelto.ECS/Extensions/Unity/IImplementor.cs → Svelto.ECS/Hybrid/IImplementor.cs View File


+ 6
- 17
Svelto.ECS/IEngine.cs View File

@@ -1,24 +1,13 @@
namespace Svelto.ECS.Internal
{
public interface IHandleEntityViewEngineAbstracted : IEngine
public interface IReactEngine: IEngine
{}
public interface IHandleEntityStructEngine<T> : IHandleEntityViewEngineAbstracted
{
void AddInternal(ref T entityView);
void RemoveInternal(ref T entityView);
}
public class EngineInfo
{
#if ENABLE_PLATFORM_PROFILER
protected EngineInfo()
{
name = GetType().FullName;
}
#endif
internal readonly string name = string.Empty;
}
public interface IReactOnAddAndRemove : IReactEngine
{}

public interface IReactOnSwap : IReactEngine
{}
}

namespace Svelto.ECS


+ 93
- 78
Svelto.ECS/IEntitiesDB.cs View File

@@ -1,26 +1,57 @@
using System;

namespace Svelto.ECS
{
public interface IEntitiesDB: IObsoleteInterfaceDb
public interface IEntitiesDB
{
/// <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 the buffer and the index of the entity inside the buffer using the input EGID
/// </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;

/// <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
/// </summary>
/// <param name="entityGid"></param>
/// <param name="index"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
bool TryQueryEntitiesAndIndex<T>(int id, int group, out uint index, out T[] array) where T : IEntityStruct;
bool TryQueryEntitiesAndIndex<T>(EGID entityGid, out uint index, out T[] array) where T : IEntityStruct;
bool TryQueryEntitiesAndIndex<T>(int id, ExclusiveGroup.ExclusiveGroupStruct group, out uint index, out T[] array) where T : IEntityStruct;
ref T QueryUniqueEntity<T>(ExclusiveGroup.ExclusiveGroupStruct group) where T : IEntityStruct;
ref T QueryUniqueEntity<T>(int group) where T : IEntityStruct;
ref T QueryEntity<T>(EGID entityGid) where T : IEntityStruct;
ref T QueryEntity<T>(int id, ExclusiveGroup.ExclusiveGroupStruct group) where T : IEntityStruct;
ref T QueryEntity<T>(int id, int group) where T : IEntityStruct;
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;

/// <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
/// </summary>
/// <param name="group"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
ref T QueryUniqueEntity<T>(ExclusiveGroup.ExclusiveGroupStruct group) where T : struct, IEntityStruct;

/// <summary>
///
/// </summary>
/// <param name="entityGid"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
ref T QueryEntity<T>(EGID entityGid) where T : struct, IEntityStruct;

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
@@ -29,13 +60,22 @@ namespace Svelto.ECS
/// <param name="count"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
T[] QueryEntities<T>(int group, out int count) where T : IEntityStruct;
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;

T[] QueryEntities<T>(ExclusiveGroup.ExclusiveGroupStruct groupStruct, out int count) where T : IEntityStruct;
(T1[], T2[]) QueryEntities<T1, T2>(int group, out int count) where T1 : IEntityStruct where T2 : IEntityStruct;
EntityCollection<T> QueryEntities<T>(ExclusiveGroup.ExclusiveGroupStruct groupStruct)
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;

(T1[], T2[]) QueryEntities<T1, T2>(ExclusiveGroup.ExclusiveGroupStruct groupStruct, out int count)
where T1 : IEntityStruct where T2 : 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
@@ -45,79 +85,54 @@ namespace Svelto.ECS
/// <param name="mapper"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
EGIDMapper<T> QueryMappedEntities<T>(int groupID) where T : IEntityStruct;
EGIDMapper<T> QueryMappedEntities<T>(ExclusiveGroup.ExclusiveGroupStruct groupStructId) where T : IEntityStruct;
/// <summary>
/// Execute an action on entities. Be sure that the action is not capturing variables
/// otherwise you will allocate memory which will have a great impact on the execution performance.
/// ExecuteOnEntities can be used to iterate safely over entities, several checks are in place
/// to be sure that everything will be done correctly.
/// Cache friendliness is guaranteed if only Entity Structs are used, but
/// </summary>
/// <param name="egid"></param>
/// <param name="action"></param>
/// <typeparam name="T"></typeparam>
void ExecuteOnEntities<T>(int groupID, EntitiesAction<T> action) where T : IEntityStruct;
void ExecuteOnEntities<T>(ExclusiveGroup.ExclusiveGroupStruct groupStructId, EntitiesAction<T> action) where T : IEntityStruct;
void ExecuteOnEntities<T, W>(int groupID, ref W value, EntitiesAction<T, W> action) where T : IEntityStruct;
void ExecuteOnEntities<T, W>(ExclusiveGroup.ExclusiveGroupStruct groupStructId, ref W value, EntitiesAction<T, W> action) where T : IEntityStruct;
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
/// 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>(AllEntitiesAction<T> action) where T : IEntityStruct;
void ExecuteOnAllEntities<T, W>(ref W value, AllEntitiesAction<T, W> action) where T : IEntityStruct;
void ExecuteOnAllEntities<T>(ExclusiveGroup[] groups, EntitiesAction<T> action) where T : IEntityStruct;
void ExecuteOnAllEntities<T, W>(ExclusiveGroup[] groups, ref W value, EntitiesAction<T, W> action) where T : IEntityStruct;
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;

/// <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
/// Execute an action on a specific Entity. Be sure that the action is not capturing variables
/// otherwise you will allocate memory which will have a great impact on the execution performance
///
/// </summary>
/// <param name="egid"></param>
/// <param name="action"></param>
/// <typeparam name="T"></typeparam>
void ExecuteOnEntity<T>(EGID egid, EntityAction<T> action) where T : IEntityStruct;
void ExecuteOnEntity<T>(int id, int groupid, EntityAction<T> action) where T : IEntityStruct;
void ExecuteOnEntity<T>(int id, ExclusiveGroup.ExclusiveGroupStruct groupid, EntityAction<T> action) where T : IEntityStruct;
void ExecuteOnEntity<T, W>(EGID egid, ref W value, EntityAction<T, W> action) where T : IEntityStruct;
void ExecuteOnEntity<T, W>(int id, int groupid, ref W value, EntityAction<T, W> action) where T : IEntityStruct;
void ExecuteOnEntity<T, W>(int id, ExclusiveGroup.ExclusiveGroupStruct groupid, ref W value, EntityAction<T, W> action) where T : IEntityStruct;

bool Exists<T>(EGID egid) where T : IEntityStruct;
bool Exists<T>(int id, int groupid) where T : IEntityStruct;
bool Exists (ExclusiveGroup.ExclusiveGroupStruct gid);
bool HasAny<T>(int group) where T:IEntityStruct;
bool HasAny<T>(ExclusiveGroup.ExclusiveGroupStruct groupStruct) where T:IEntityStruct;
int Count<T>(ExclusiveGroup.ExclusiveGroupStruct groupStruct) where T:IEntityStruct;
int Count<T>(int groupStruct) where T:IEntityStruct;
}
/// <returns></returns>
bool Exists<T>(EGID egid) where T : struct, IEntityStruct;
bool Exists(ExclusiveGroup.ExclusiveGroupStruct gid);

public delegate void EntityAction<T, W>(ref T target, ref W value);
public delegate void EntityAction<T>(ref T target);
/// <summary>
///
/// </summary>
/// <param name="group"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
bool HasAny<T>(ExclusiveGroup.ExclusiveGroupStruct groupStruct) where T : struct, IEntityStruct;

public delegate void AllEntitiesAction<T, W>(ref T target, ref W value, IEntitiesDB entitiesDb);
public delegate void AllEntitiesAction<T>(ref T target, IEntitiesDB entitiesDb);
public delegate void EntitiesAction<T, W>(ref T target, ref W value, EntityActionData extraParams);
public delegate void EntitiesAction<T>(ref T target, EntityActionData extraParams);
/// <summary>
///
/// </summary>
/// <param name="groupStruct"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
uint Count<T>(ExclusiveGroup.ExclusiveGroupStruct groupStruct) where T : struct, IEntityStruct;

public struct EntityActionData
{
public readonly IEntitiesDB entitiesDB;
public readonly int entityIndex;

public EntityActionData(IEntitiesDB entitiesDb, int index)
{
this.entitiesDB = entitiesDb;
entityIndex = index;
}
/// <summary>
///
/// </summary>
/// <param name="egid"></param>
/// <typeparam name="T"></typeparam>
void PublishEntityChange<T>(EGID egid) where T : unmanaged, IEntityStruct;
}
}

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

@@ -6,7 +6,7 @@ namespace Svelto.ECS
public interface IEntityBuilder
{
void BuildEntityAndAddToList(ref ITypeSafeDictionary dictionary, EGID entityID, object[] implementors);
ITypeSafeDictionary Preallocate(ref ITypeSafeDictionary dictionary, int size);
ITypeSafeDictionary Preallocate(ref ITypeSafeDictionary dictionary, uint size);

Type GetEntityType();
}

+ 2
- 1
Svelto.ECS/IEntityDescriptorHolder.cs View File

@@ -3,7 +3,8 @@ namespace Svelto.ECS
public interface IEntityDescriptorHolder
{
IEntityDescriptor GetDescriptor();
string groupName { get; }
ushort id { get; }
}
}

+ 24
- 9
Svelto.ECS/IEntityFactory.cs View File

@@ -16,13 +16,14 @@ namespace Svelto.ECS
/// </summary>
public interface IEntityFactory
{
/// <summary>
///where performance is critical, you may wish to pre allocate the space needed
///to store the entities
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="size"></param>
void PreallocateEntitySpace<T>(ExclusiveGroup.ExclusiveGroupStruct groupStructId, int size)
/// <summary>
/// where performance is critical, you may wish to pre allocate the space needed
/// to store the entities
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="groupStructId"></param>
/// <param name="size"></param>
void PreallocateEntitySpace<T>(ExclusiveGroup.ExclusiveGroupStruct groupStructId, uint size)
where T : IEntityDescriptor, new();
/// <summary>
@@ -39,11 +40,25 @@ namespace Svelto.ECS
/// <param name="groupStructId"></param>
/// <param name="ed"></param>
/// <param name="implementors"></param>
EntityStructInitializer BuildEntity<T>(int entityID, ExclusiveGroup.ExclusiveGroupStruct groupStructId,
EntityStructInitializer BuildEntity<T>(uint entityID, ExclusiveGroup.ExclusiveGroupStruct groupStructId,
object[] implementors = null)
where T : IEntityDescriptor, new();
EntityStructInitializer BuildEntity<T>(EGID egid, object[] implementors = null)
where T:IEntityDescriptor, new();

#if REAL_ID
/// <summary>
/// BuildEntity version without specifying the entity ID. The complete EGID will be found inside
/// the EntityStructInitializer and/or the single entity components
/// </summary>
/// <param name="groupID"></param>
/// <param name="implementors"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
EntityStructInitializer BuildEntity<T>(ExclusiveGroup.ExclusiveGroupStruct groupID, object[] implementors = null)
where T : IEntityDescriptor, new();
#endif
/// <summary>
/// When the type of the entity is not known (this is a special case!) an EntityDescriptorInfo
/// can be built in place of the generic parameter T.
@@ -52,7 +67,7 @@ namespace Svelto.ECS
/// <param name="entityDescriptor"></param>
/// <param name="implementors"></param>
///
EntityStructInitializer BuildEntity<T>(int entityID, ExclusiveGroup.ExclusiveGroupStruct groupStructId,
EntityStructInitializer BuildEntity<T>(uint entityID, ExclusiveGroup.ExclusiveGroupStruct groupStructId,
T descriptorEntity,
object[] implementors = null)
where T : IEntityDescriptor;


+ 9
- 9
Svelto.ECS/IEntityFunctions.cs View File

@@ -5,21 +5,21 @@ 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>(int entityID, int groupID) where T : IEntityDescriptor, new();
void RemoveEntity<T>(int entityID, ExclusiveGroup.ExclusiveGroupStruct groupID) where T : IEntityDescriptor, new();
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>(int groupID) 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(int groupID);
void RemoveGroupAndEntities(uint groupID);
void RemoveGroupAndEntities(ExclusiveGroup.ExclusiveGroupStruct groupID);
void SwapEntityGroup<T>(int entityID, ExclusiveGroup.ExclusiveGroupStruct fromGroupID, ExclusiveGroup.ExclusiveGroupStruct toGroupID) where T : IEntityDescriptor, new();
void SwapEntityGroup<T>(EGID id, ExclusiveGroup.ExclusiveGroupStruct toGroupID) where T : IEntityDescriptor, new();
void SwapEntityGroup<T>(EGID id, ExclusiveGroup.ExclusiveGroupStruct toGroupID, ExclusiveGroup.ExclusiveGroupStruct mustBeFromGroup) where T : IEntityDescriptor, new();
void SwapEntityGroup<T>(uint entityID, ExclusiveGroup.ExclusiveGroupStruct fromGroupID, ExclusiveGroup.ExclusiveGroupStruct toGroupID) where T : IEntityDescriptor, new();
void SwapEntityGroup<T>(EGID fromID, ExclusiveGroup.ExclusiveGroupStruct toGroupID) where T : IEntityDescriptor, new();
void SwapEntityGroup<T>(EGID fromID, ExclusiveGroup.ExclusiveGroupStruct toGroupID, ExclusiveGroup.ExclusiveGroupStruct mustBeFromGroup) where T : IEntityDescriptor, new();
void SwapEntityGroup<T>(EGID id, EGID toId) where T : IEntityDescriptor, new();
void SwapEntityGroup<T>(EGID id, EGID toId, ExclusiveGroup.ExclusiveGroupStruct mustBeFromGroup) where T : IEntityDescriptor, new();
void SwapEntityGroup<T>(EGID fromID, EGID toId) where T : IEntityDescriptor, new();
void SwapEntityGroup<T>(EGID fromID, EGID toId, ExclusiveGroup.ExclusiveGroupStruct mustBeFromGroup) where T : IEntityDescriptor, new();
}
}

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

@@ -2,6 +2,9 @@ namespace Svelto.ECS
{
///<summary>EntityStruct MUST implement IEntiyStruct</summary>
public interface IEntityStruct
{}
public interface INeedEGID
{
EGID ID { get; set; }
}

+ 0
- 7
Svelto.ECS/IEntityViewStruct.cs View File

@@ -1,7 +0,0 @@
namespace Svelto.ECS.Hybrid
{
///<summary>EntityViewStructs MUST implement IEntityViewStruct</summary>
public interface IEntityViewStruct:IEntityStruct
{}
}


+ 0
- 51
Svelto.ECS/IObsoleteInterfaceDb.cs View File

@@ -1,51 +0,0 @@
using System;
using Svelto.DataStructures;

namespace Svelto.ECS
{
public interface IObsoleteInterfaceDb
{
/// <summary>
/// All the EntityView related methods are left for back compatibility, but
/// shouldn't be used anymore. Always pick EntityViewStruct or EntityStruct
/// over EntityView
/// </summary>
[Obsolete]
ReadOnlyCollectionStruct<T> QueryEntityViews<T>(int group) where T : class, IEntityStruct;
[Obsolete]
ReadOnlyCollectionStruct<T> QueryEntityViews<T>(ExclusiveGroup.ExclusiveGroupStruct group) where T : class, IEntityStruct;
/// <summary>
/// All the EntityView related methods are left for back compatibility, but
/// shouldn't be used anymore. Always pick EntityViewStruct or EntityStruct
/// over EntityView
/// </summary>
[Obsolete]
bool TryQueryEntityView<T>(EGID egid, out T entityView) where T : class, IEntityStruct;
[Obsolete]
bool TryQueryEntityView<T>(int id, ExclusiveGroup.ExclusiveGroupStruct group, out T entityView) where T : class, IEntityStruct;
/// <summary>
/// All the EntityView related methods are left for back compatibility, but
/// shouldn't be used anymore. Always pick EntityViewStruct or EntityStruct
/// over EntityView
/// </summary>
[Obsolete]
T QueryEntityView<T>(EGID egid) where T : class, IEntityStruct;
[Obsolete]
T QueryEntityView<T>(int id, ExclusiveGroup.ExclusiveGroupStruct group) where T : class, 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
/// </summary>
/// <param name="entityGid"></param>
/// <param name="index"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
[Obsolete]
T[] QueryEntitiesAndIndex<T>(EGID entityGid, out uint index) where T : IEntityStruct;
[Obsolete]
T[] QueryEntitiesAndIndex<T>(int id, ExclusiveGroup.ExclusiveGroupStruct group, out uint index) where T : IEntityStruct;
[Obsolete]
T[] QueryEntitiesAndIndex<T>(int id, int group, out uint index) where T : IEntityStruct;
}
}

+ 10
- 0
Svelto.ECS/IReactOnAddAndRemove.cs View File

@@ -0,0 +1,10 @@
using Svelto.ECS.Internal;

namespace Svelto.ECS
{
public interface IReactOnAddAndRemove<T> : IReactOnAddAndRemove where T : IEntityStruct
{
void Add(ref T entityView);
void Remove(ref T entityView);
}
}

+ 10
- 0
Svelto.ECS/IReactOnSwap.cs View File

@@ -0,0 +1,10 @@
using Svelto.ECS.Internal;

namespace Svelto.ECS
{
public interface IReactOnSwap<T> : IReactOnSwap where T : IEntityStruct
{
void MovedTo(ref T entityView, ExclusiveGroup.ExclusiveGroupStruct previousGroup);
void MovedFrom(ref T entityView, ExclusiveGroup.ExclusiveGroupStruct previousGroupValue);
}
}

+ 0
- 44
Svelto.ECS/MultiEntitiesEngine.cs View File

@@ -1,44 +0,0 @@
using Svelto.ECS.Internal;

namespace Svelto.ECS
{
public abstract class MultiEntitiesEngine<T, U> : SingleEntityEngine<T>, IHandleEntityStructEngine<U>
where U : IEntityStruct where T : IEntityStruct
{
public void AddInternal(ref U entityView)
{ Add(ref entityView); }
public void RemoveInternal(ref U entityView)
{ Remove(ref entityView); }
protected abstract void Add(ref U entityView);
protected abstract void Remove(ref U entityView);
}
public abstract class MultiEntitiesEngine<T, U, V> : MultiEntitiesEngine<T, U>, IHandleEntityStructEngine<V>
where V : IEntityStruct where U : IEntityStruct where T : IEntityStruct
{
public void AddInternal(ref V entityView)
{ Add(ref entityView); }
public void RemoveInternal(ref V entityView)
{ Remove(ref entityView); }
protected abstract void Add(ref V entityView);
protected abstract void Remove(ref V entityView);
}

/// <summary>
/// Please do not add more MultiEntityViewsEngine if you use more than 4 nodes, your engine has
/// already too many responsibilities.
/// </summary>
public abstract class MultiEntitiesEngine<T, U, V, W> : MultiEntitiesEngine<T, U, V>, IHandleEntityStructEngine<W>
where W : IEntityStruct where V : IEntityStruct where U : IEntityStruct where T : IEntityStruct
{
public void AddInternal(ref W entityView)
{ Add(ref entityView); }
public void RemoveInternal(ref W entityView)
{ Remove(ref entityView); }
protected abstract void Add(ref W entityView);
protected abstract void Remove(ref W entityView);
}
}

+ 0
- 45
Svelto.ECS/MultiEntityViewsEngine.cs View File

@@ -1,45 +0,0 @@
using Svelto.ECS.Internal;

namespace Svelto.ECS
{
public abstract class MultiEntityViewsEngine<T, U> : SingleEntityViewEngine<T>, IHandleEntityStructEngine<U>
where U : class, IEntityStruct where T : class, IEntityStruct
{
public void AddInternal(ref U entityView)
{ Add(entityView); }
public void RemoveInternal(ref U entityView)
{ Remove(entityView); }
protected abstract void Add(U entityView);
protected abstract void Remove(U entityView);
}

public abstract class MultiEntityViewsEngine<T, U, V> : MultiEntityViewsEngine<T, U>, IHandleEntityStructEngine<V>
where V : class, IEntityStruct where U : class, IEntityStruct where T : class, IEntityStruct
{
public void AddInternal(ref V entityView)
{ Add(entityView); }
public void RemoveInternal(ref V entityView)
{ Remove(entityView); }
protected abstract void Add(V entityView);
protected abstract void Remove(V entityView);
}

/// <summary>
/// Please do not add more MultiEntityViewsEngine
/// if you use more than 4 nodes, your engine has
/// already too many responsabilities.
/// </summary>
public abstract class MultiEntityViewsEngine<T, U, V, W> : MultiEntityViewsEngine<T, U, V>, IHandleEntityStructEngine<W>
where W : class, IEntityStruct where V : class, IEntityStruct where U : class, IEntityStruct where T : class, IEntityStruct
{
public void AddInternal(ref W entityView)
{ Add(entityView); }
public void RemoveInternal(ref W entityView)
{ Remove(entityView); }
protected abstract void Add(W entityView);
protected abstract void Remove(W entityView);
}
}

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

@@ -99,7 +99,7 @@ namespace Svelto.ECS
/// </summary>
public class Sequencer<S> where S: Sequencer<S>, new()
{
protected void SetSequence(Steps steps)
public void SetSequence(Steps steps)
{
_steps = steps;
}


+ 0
- 16
Svelto.ECS/SingleEntityEngine.cs View File

@@ -1,16 +0,0 @@
using Svelto.ECS.Internal;

namespace Svelto.ECS
{
public abstract class SingleEntityEngine<T> : EngineInfo, IHandleEntityStructEngine<T> where T : IEntityStruct
{
public void AddInternal(ref T entityView)
{ Add(ref entityView); }

public void RemoveInternal(ref T entityView)
{ Remove(ref entityView); }

protected abstract void Add(ref T entityView);
protected abstract void Remove(ref T entityView);
}
}

+ 0
- 16
Svelto.ECS/SingleEntityViewEngine.cs View File

@@ -1,16 +0,0 @@
using Svelto.ECS.Internal;

namespace Svelto.ECS
{
public abstract class SingleEntityViewEngine<T> : EngineInfo, IHandleEntityStructEngine<T> where T : class, IEntityStruct
{
public void AddInternal(ref T entityView)
{ Add(entityView); }

public void RemoveInternal(ref T entityView)
{ Remove(entityView); }

protected abstract void Add(T entityView);
protected abstract void Remove(T entityView);
}
}

+ 6
- 1
Svelto.ECS/Svelto.ECS.asmdef View File

@@ -6,5 +6,10 @@
"optionalUnityReferences": [],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": []
}

+ 11
- 11
Svelto.ECS/Svelto.ECS.csproj View File

@@ -1,21 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>Svelto.ECS</AssemblyName>
<LangVersion>6</LangVersion>
<LangVersion>7.3</LangVersion>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<UseSharedCompilation>false</UseSharedCompilation>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<UseSharedCompilation>false</UseSharedCompilation>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Reflection" Version="4.3.0" />
<PackageReference Include="System.Reflection.Emit" Version="4.3.0" />
<PackageReference Include="System.Reflection.Emit.ILGeneration" Version="4.3.0" />
<PackageReference Include="System.Reflection.Emit.Lightweight" Version="4.3.0" />
<PackageReference Include="System.Reflection.Extensions" Version="4.3.0" />
<PackageReference Include="System.Reflection.Primitives" Version="4.3.0" />
<PackageReference Include="System.Reflection.TypeExtensions" Version="4.4.0" />
<ProjectReference Include="..\Svelto.Common\Svelto.Common.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Reflection.Emit.Lightweight">
<HintPath>C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.netcore.app\2.0.0\ref\netcoreapp2.0\System.Reflection.Emit.Lightweight.dll</HintPath>
</Reference>
<PackageReference Include="System.Memory" Version="4.5.2" />
</ItemGroup>
</Project>

Loading…
Cancel
Save