diff --git a/DBC.cs b/DBC.cs
index d73fee3..e9fae93 100644
--- a/DBC.cs
+++ b/DBC.cs
@@ -1,7 +1,8 @@
-using System;
-#if PROFILER || !DEBUG
+#if DISABLE_DBC || !DEBUG || PROFILER
+#define DISABLE_CHECKS
using System.Diagnostics;
#endif
+using System;
namespace DBC.ECS
{
@@ -59,7 +60,7 @@ namespace DBC.ECS
///
/// Precondition check.
///
-#if PROFILER || !DEBUG
+#if DISABLE_DBC
[Conditional("__NEVER_DEFINED__")]
#endif
public static void Require(bool assertion, string message)
@@ -79,7 +80,7 @@ namespace DBC.ECS
/// Precondition check.
///
///
-#if PROFILER || !DEBUG
+#if DISABLE_DBC
[Conditional("__NEVER_DEFINED__")]
#endif
public static void Require(bool assertion, string message, Exception inner)
@@ -99,7 +100,7 @@ namespace DBC.ECS
/// Precondition check.
///
///
-#if PROFILER || !DEBUG
+#if DISABLE_DBC
[Conditional("__NEVER_DEFINED__")]
#endif
public static void Require(bool assertion)
@@ -119,7 +120,7 @@ namespace DBC.ECS
/// Postcondition check.
///
///
-#if PROFILER || !DEBUG
+#if DISABLE_DBC
[Conditional("__NEVER_DEFINED__")]
#endif
public static void Ensure(bool assertion, string message)
@@ -139,7 +140,7 @@ namespace DBC.ECS
/// Postcondition check.
///
///
-#if PROFILER || !DEBUG
+#if DISABLE_DBC
[Conditional("__NEVER_DEFINED__")]
#endif
public static void Ensure(bool assertion, string message, Exception inner)
@@ -159,7 +160,7 @@ namespace DBC.ECS
/// Postcondition check.
///
///
-#if PROFILER || !DEBUG
+#if DISABLE_DBC
[Conditional("__NEVER_DEFINED__")]
#endif
public static void Ensure(bool assertion)
@@ -179,7 +180,7 @@ namespace DBC.ECS
/// Invariant check.
///
///
-#if PROFILER || !DEBUG
+#if DISABLE_DBC
[Conditional("__NEVER_DEFINED__")]
#endif
public static void Invariant(bool assertion, string message)
@@ -199,7 +200,7 @@ namespace DBC.ECS
/// Invariant check.
///
///
-#if PROFILER || !DEBUG
+#if DISABLE_DBC
[Conditional("__NEVER_DEFINED__")]
#endif
public static void Invariant(bool assertion, string message, Exception inner)
@@ -219,7 +220,7 @@ namespace DBC.ECS
/// Invariant check.
///
///
-#if PROFILER || !DEBUG
+#if DISABLE_DBC
[Conditional("__NEVER_DEFINED__")]
#endif
public static void Invariant(bool assertion)
@@ -238,7 +239,7 @@ namespace DBC.ECS
///
/// Assertion check.
///
-#if PROFILER || !DEBUG
+#if DISABLE_DBC
[Conditional("__NEVER_DEFINED__")]
#endif
public static void Assert(bool assertion, string message)
@@ -258,7 +259,7 @@ namespace DBC.ECS
/// Assertion check.
///
///
-#if PROFILER || !DEBUG
+#if DISABLE_DBC
[Conditional("__NEVER_DEFINED__")]
#endif
public static void Assert(bool assertion, string message, Exception inner)
@@ -278,7 +279,7 @@ namespace DBC.ECS
/// Assertion check.
///
///
-#if PROFILER || !DEBUG
+#if DISABLE_DBC
[Conditional("__NEVER_DEFINED__")]
#endif
public static void Assert(bool assertion)
diff --git a/Svelto.ECS/EnginesRoot.Engines.cs b/Svelto.ECS/EnginesRoot.Engines.cs
index 1438ee0..0ca68ef 100644
--- a/Svelto.ECS/EnginesRoot.Engines.cs
+++ b/Svelto.ECS/EnginesRoot.Engines.cs
@@ -14,17 +14,18 @@ namespace Svelto.ECS
{
public partial class EnginesRoot : IDisposable
{
+#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR
static EnginesRoot()
{
-#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR
+
///
/// I still need to find a good solution for this. Need to move somewhere else
///
UnityEngine.GameObject debugEngineObject = new UnityEngine.GameObject("Svelto.ECS.Profiler");
debugEngineObject.gameObject.AddComponent();
UnityEngine.GameObject.DontDestroyOnLoad(debugEngineObject);
-#endif
}
+#endif
///
/// Engines root contextualize your engines and entities. You don't need to limit yourself to one EngineRoot
@@ -34,21 +35,22 @@ namespace Svelto.ECS
/// The EntitySubmissionScheduler cannot hold an EnginesRoot reference, that's why
/// it must receive a weak reference of the EnginesRoot callback.
///
- public EnginesRoot(EntitySubmissionScheduler entityViewScheduler)
+ public EnginesRoot(IEntitySubmissionScheduler entityViewScheduler)
{
_entitiesOperations = new FasterList();
_entityEngines = new Dictionary>();
_otherEngines = new FasterList();
_disposableEngines = new FasterList();
+ _transientEntitiesOperations = new FasterList();
_groupEntityDB = new FasterDictionary>();
- _groupedGroups = new Dictionary>();
+ _groupsPerEntity = new Dictionary>();
_groupedEntityToAdd = new DoubleBufferedEntitiesToAdd>>();
- _DB = new EntitiesDB(_groupEntityDB, _groupedGroups);
+ _DB = new EntitiesDB(_groupEntityDB, _groupsPerEntity);
_scheduler = entityViewScheduler;
- _scheduler.Schedule(new WeakAction(SubmitEntityViews));
+ _scheduler.onTick = new WeakAction(SubmitEntityViews);
}
public void AddEngine(IEngine engine)
diff --git a/Svelto.ECS/EnginesRoot.Entities.cs b/Svelto.ECS/EnginesRoot.Entities.cs
index 34f05f6..61c54db 100644
--- a/Svelto.ECS/EnginesRoot.Entities.cs
+++ b/Svelto.ECS/EnginesRoot.Entities.cs
@@ -1,7 +1,8 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
-using Svelto.DataStructures.Experimental;
+ using Svelto.DataStructures;
+ using Svelto.DataStructures.Experimental;
using Svelto.ECS.Internal;
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR
@@ -58,11 +59,9 @@ namespace Svelto.ECS
#endif
var dic = EntityFactory.BuildGroupedEntities(entityID,
_groupedEntityToAdd.current,
- descriptorEntitiesToBuild,
+ descriptorEntitiesToBuild,
implementors);
- _newEntitiesBuiltToProcess++;
-
return new EntityStructInitializer(entityID, dic);
}
@@ -96,7 +95,6 @@ namespace Svelto.ECS
}
}
}
-
///--------------------------------------------
void Preallocate(int groupID, int size) where T : IEntityDescriptor, new()
@@ -188,8 +186,8 @@ namespace Svelto.ECS
}
FasterDictionary groupedGroup;
- if (_groupedGroups.TryGetValue(entityType, out groupedGroup) == false)
- groupedGroup = _groupedGroups[entityType] = new FasterDictionary();
+ if (_groupsPerEntity.TryGetValue(entityType, out groupedGroup) == false)
+ groupedGroup = _groupsPerEntity[entityType] = new FasterDictionary();
groupedGroup[toGroupID] = dictionaryOfEntities;
}
@@ -202,7 +200,7 @@ namespace Svelto.ECS
if (fromTypeSafeDictionary.Count == 0) //clean up
{
- _groupedGroups[entityType].Remove(entityGID.groupID);
+ _groupsPerEntity[entityType].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
@@ -216,7 +214,7 @@ namespace Svelto.ECS
foreach (var dictionaryOfEntities in dictionariesOfEntities)
{
dictionaryOfEntities.Value.RemoveEntitiesFromEngines(_entityEngines);
- var groupedGroupOfEntities = _groupedGroups[dictionaryOfEntities.Key];
+ var groupedGroupOfEntities = _groupsPerEntity[dictionaryOfEntities.Key];
groupedGroupOfEntities.Remove(groupID);
}
@@ -240,7 +238,6 @@ namespace Svelto.ECS
}
readonly EntitiesDB _DB;
- int _newEntitiesBuiltToProcess;
Type _entityInfoView = typeof(EntityInfoView);
}
diff --git a/Svelto.ECS/EnginesRoot.Submission.cs b/Svelto.ECS/EnginesRoot.Submission.cs
index 5db8dd5..f73459e 100644
--- a/Svelto.ECS/EnginesRoot.Submission.cs
+++ b/Svelto.ECS/EnginesRoot.Submission.cs
@@ -1,9 +1,12 @@
-using System;
+using System;
using System.Collections.Generic;
+using System.Diagnostics;
+using Svelto.Common;
using Svelto.DataStructures;
using Svelto.DataStructures.Experimental;
using Svelto.ECS.Internal;
using Svelto.ECS.Schedulers;
+using Console = Svelto.Utilities.Console;
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR
using Svelto.ECS.Profiler;
@@ -15,69 +18,87 @@ namespace Svelto.ECS
{
void SubmitEntityViews()
{
- var entitiesOperations = _entitiesOperations.ToArrayFast();
- for (int i = 0; i < _entitiesOperations.Count; i++)
+ using (new PlatformProfiler("Svelto.ECS submit"))
{
+ if (_entitiesOperations.Count > 0)
+ {
+ _transientEntitiesOperations.FastClear();
+ _transientEntitiesOperations.AddRange(_entitiesOperations);
+ _entitiesOperations.FastClear();
+ var entitiesOperations = _transientEntitiesOperations.ToArrayFast();
+ for (var i = 0; i < _transientEntitiesOperations.Count; i++)
+ {
+ try
+ {
+ switch (entitiesOperations[i].type)
+ {
+ case EntitySubmitOperationType.Swap:
+ SwapEntityGroup(entitiesOperations[i].builders, entitiesOperations[i].id,
+ entitiesOperations[i].fromGroupID, entitiesOperations[i].toGroupID);
+ break;
+ case EntitySubmitOperationType.Remove:
+ MoveEntity(entitiesOperations[i].builders,
+ new EGID(entitiesOperations[i].id, entitiesOperations[i].fromGroupID));
+ break;
+ case EntitySubmitOperationType.RemoveGroup:
+ RemoveGroupAndEntitiesFromDB(entitiesOperations[i].fromGroupID);
+ break;
+ }
+ }
+ catch (Exception e)
+ {
+#if DEBUG
+ var str = "Entity ".FastConcat(entitiesOperations[i].type.ToString(),
+ " with used ID is about to be built: ")
+ .FastConcat(" id: ")
+ .FastConcat(entitiesOperations[i].id)
+ .FastConcat(" from groupid: ")
+ .FastConcat(entitiesOperations[i].fromGroupID)
+ .FastConcat(" to groupid: ")
+ .FastConcat(entitiesOperations[i].toGroupID);
+
+ Console.LogError(e.Message.FastConcat(" ", str, " ", entitiesOperations[i].trace));
+
+ throw;
+#else
+ Console.LogException(e);
+#endif
+ }
+ }
+ }
+
try
{
- switch (entitiesOperations[i].type)
+ if (_groupedEntityToAdd.current.Count > 0)
{
- case EntitySubmitOperationType.Swap:
- SwapEntityGroup(entitiesOperations[i].builders, entitiesOperations[i].id,
- entitiesOperations[i].fromGroupID, entitiesOperations[i].toGroupID);
- break;
- case EntitySubmitOperationType.Remove:
- MoveEntity(entitiesOperations[i].builders,
- new EGID(entitiesOperations[i].id, entitiesOperations[i].fromGroupID));
- break;
- case EntitySubmitOperationType.RemoveGroup:
- RemoveGroupAndEntitiesFromDB(entitiesOperations[i].fromGroupID);
- break;
+ //use other as source from now on
+ //current will be use to write new entityViews
+ _groupedEntityToAdd.Swap();
+
+ //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);
+
+ //other can be cleared now, but let's avoid deleting the dictionary every time
+ _groupedEntityToAdd.ClearOther();
}
}
- catch (ECSException e)
+ catch (Exception e)
{
- Svelto.Utilities.Console.LogError(e.Message.FastConcat(" ", entitiesOperations[i].trace));
-
+ Console.LogException(e);
#if DEBUG
throw;
-#endif
+#endif
}
}
-
- _entitiesOperations.FastClear();
-
- int numberOfReenteringLoops = 0;
-
- //are there new entities built to process?
- while ( _newEntitiesBuiltToProcess > 0)
- {
- _newEntitiesBuiltToProcess = 0;
- //use other as source from now on
- //current will be use to write new entityViews
- _groupedEntityToAdd.Swap();
-
- //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 calback 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.
- if (_groupedEntityToAdd.other.Count > 0)
- AddEntityViewsToTheDBAndSuitableEngines(_groupedEntityToAdd.other);
-
- //other can be cleared now, but let's avoid deleting the dictionary every time
- _groupedEntityToAdd.ClearOther();
-
- if (numberOfReenteringLoops > 5)
- throw new Exception("possible infinite loop found creating Entities inside IEntityViewsEngine Add method, please consider building entities outside IEntityViewsEngine Add method");
-
- numberOfReenteringLoops++;
- }
}
- //todo: groupsToSubmit can be simplified as data structure?
- void AddEntityViewsToTheDBAndSuitableEngines(FasterDictionary> groupsOfEntitiesToSubmit)
+ void AddEntityViewsToTheDBAndSuitableEngines(FasterDictionary> groupsOfEntitiesToSubmit)
{
//each group is indexed by entity view type. for each type there is a dictionary indexed by entityID
foreach (var groupOfEntitiesToSubmit in groupsOfEntitiesToSubmit)
@@ -97,8 +118,8 @@ namespace Svelto.ECS
if (groupDB.TryGetValue(entityViewTypeSafeDictionary.Key, out dbDic) == false)
dbDic = groupDB[entityViewTypeSafeDictionary.Key] = entityViewTypeSafeDictionary.Value.Create();
- if (_groupedGroups.TryGetValue(entityViewTypeSafeDictionary.Key, out groupedGroup) == false)
- groupedGroup = _groupedGroups[entityViewTypeSafeDictionary.Key] =
+ if (_groupsPerEntity.TryGetValue(entityViewTypeSafeDictionary.Key, out groupedGroup) == false)
+ groupedGroup = _groupsPerEntity[entityViewTypeSafeDictionary.Key] =
new FasterDictionary();
//Fill the DB with the entity views generate this frame.
@@ -117,20 +138,25 @@ namespace Svelto.ECS
}
}
}
-
+
+ readonly FasterList _entitiesOperations;
+
+ readonly DoubleBufferedEntitiesToAdd>>
+ _groupedEntityToAdd;
+
+ //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> _groupsPerEntity; //yes I am being sarcastic
+
//one datastructure rule them all:
//split by group
//split by type per group. It's possible to get all the entities of a give type T per group thanks
//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> _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> _groupedGroups; //yes I am being sarcastic
- readonly DoubleBufferedEntitiesToAdd>>
- _groupedEntityToAdd;
- readonly EntitySubmissionScheduler _scheduler;
- readonly FasterList _entitiesOperations;
+ readonly IEntitySubmissionScheduler _scheduler;
+ readonly FasterList _transientEntitiesOperations;
}
}
\ No newline at end of file
diff --git a/Svelto.ECS/EntityBuilder.cs b/Svelto.ECS/EntityBuilder.cs
index 29f631b..a464007 100644
--- a/Svelto.ECS/EntityBuilder.cs
+++ b/Svelto.ECS/EntityBuilder.cs
@@ -41,7 +41,7 @@ namespace Svelto.ECS
SubCheckFields(fieldFieldType);
}
- if (type.Assembly == Assembly.GetCallingAssembly())
+ if (type.Assembly == Assembly.GetCallingAssembly() && type != typeof(Svelto.ECS.EGID))
{
var methods = type.GetMethods(BindingFlags.Public |
BindingFlags.Instance | BindingFlags.DeclaredOnly);
@@ -141,7 +141,8 @@ namespace Svelto.ECS
public class EntityStructException : Exception
{
- public EntityStructException(Type fieldType):base("EntityStruct must contains only value types and no public methods! " + fieldType.ToString())
+ public EntityStructException(Type fieldType) :
+ base("EntityStruct must contains only value types and no public methods! " + fieldType.ToString())
{}
}
}
\ No newline at end of file
diff --git a/Svelto.ECS/EntitySubmissionScheduler.cs b/Svelto.ECS/EntitySubmissionScheduler.cs
index 09335fd..93e4b4c 100644
--- a/Svelto.ECS/EntitySubmissionScheduler.cs
+++ b/Svelto.ECS/EntitySubmissionScheduler.cs
@@ -2,8 +2,8 @@ using Svelto.WeakEvents;
namespace Svelto.ECS.Schedulers
{
- public abstract class EntitySubmissionScheduler
+ public interface IEntitySubmissionScheduler
{
- public abstract void Schedule(WeakAction submitEntityViews);
+ WeakAction onTick { set; }
}
}
\ No newline at end of file
diff --git a/Svelto.ECS/EntitySubmitOperation.cs b/Svelto.ECS/EntitySubmitOperation.cs
index 6a1510a..66c098c 100644
--- a/Svelto.ECS/EntitySubmitOperation.cs
+++ b/Svelto.ECS/EntitySubmitOperation.cs
@@ -13,7 +13,11 @@ namespace Svelto.ECS
public string trace;
#endif
- public EntitySubmitOperation(EntitySubmitOperationType operation, int entityId, int fromGroupId, int toGroupId, IEntityBuilder[] builders)
+ public EntitySubmitOperation(EntitySubmitOperationType operation,
+ int entityId,
+ int fromGroupId,
+ int toGroupId,
+ IEntityBuilder[] builders)
{
type = operation;
this.builders = builders;
@@ -30,6 +34,6 @@ namespace Svelto.ECS
{
Swap,
Remove,
- RemoveGroup
+ RemoveGroup,
}
}
\ No newline at end of file
diff --git a/Svelto.ECS/Extensions/Unity/UnityEntitySubmissionScheduler.cs b/Svelto.ECS/Extensions/Unity/UnityEntitySubmissionScheduler.cs
index fbaa798..3da402a 100644
--- a/Svelto.ECS/Extensions/Unity/UnityEntitySubmissionScheduler.cs
+++ b/Svelto.ECS/Extensions/Unity/UnityEntitySubmissionScheduler.cs
@@ -7,21 +7,8 @@ namespace Svelto.ECS.Schedulers.Unity
{
//The EntitySubmissionScheduler has been introduced to make the entity views submission logic platform independent
//You can customize the scheduler if you wish
-
- public class UnityEntitySubmissionScheduler : EntitySubmissionScheduler
+ public class UnityEntitySubmissionScheduler : IEntitySubmissionScheduler
{
- public UnityEntitySubmissionScheduler()
- {
- GameObject go = new GameObject("ECSScheduler");
-
- _scheduler = go.AddComponent();
- }
-
- public override void Schedule(WeakAction submitEntityViews)
- {
- _scheduler.OnTick = submitEntityViews;
- }
-
class Scheduler : MonoBehaviour
{
IEnumerator Start()
@@ -30,19 +17,34 @@ namespace Svelto.ECS.Schedulers.Unity
{
yield return _wait;
- if (OnTick.IsValid)
- OnTick.Invoke();
+ if (onTick.IsValid)
+ onTick.Invoke();
else
yield break;
+
}
}
- internal WeakAction OnTick;
-
readonly WaitForEndOfFrame _wait = new WaitForEndOfFrame();
+
+ public WeakAction onTick;
+ }
+
+ public WeakAction onTick
+ {
+ set
+ {
+ if (_scheduler == null)
+ {
+ GameObject go = new GameObject("ECSScheduler");
+
+ _scheduler = go.AddComponent();
+ }
+ _scheduler.onTick = value;
+ }
}
- readonly Scheduler _scheduler;
+ Scheduler _scheduler;
}
}
#endif
\ No newline at end of file
diff --git a/Svelto.ECS/SimpleSubmissionEntityViewScheduler.cs b/Svelto.ECS/SimpleSubmissionEntityViewScheduler.cs
index 57d3b97..d316c5c 100644
--- a/Svelto.ECS/SimpleSubmissionEntityViewScheduler.cs
+++ b/Svelto.ECS/SimpleSubmissionEntityViewScheduler.cs
@@ -5,18 +5,13 @@ namespace Svelto.ECS
{
//This scheduler shouldn't be used in production and it's meant to be
//used for Unit Tests only
- public class SimpleSubmissionEntityViewScheduler : EntitySubmissionScheduler
+ public class SimpleSubmissionEntityViewScheduler : IEntitySubmissionScheduler
{
public void SubmitEntities()
{
- _submitEntityViews.Invoke();
+ onTick.Invoke();
}
-
- public override void Schedule(WeakAction submitEntityViews)
- {
- _submitEntityViews = submitEntityViews;
- }
-
- WeakAction _submitEntityViews;
+
+ public WeakAction onTick { set; private get; }
}
}
\ No newline at end of file