@@ -1,17 +1,18 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
#if !DEBUG || PROFILER | |||
#define DISABLE_CHECKS | |||
using System.Diagnostics; | |||
using Svelto.ECS.Internal; | |||
#if DEBUG && !PROFILER | |||
#define _USE_IT | |||
#endif | |||
using System; | |||
using System.Collections.Generic; | |||
using Svelto.ECS.Internal; | |||
namespace Svelto.ECS | |||
{ | |||
public partial class EnginesRoot | |||
{ | |||
[Conditional("_USE_IT")] | |||
#if DISABLE_CHECKS | |||
[Conditional("_CHECKS_DISABLED")] | |||
#endif | |||
void CheckRemoveEntityID(EGID entityID, IEntityDescriptor descriptorEntity) | |||
{ | |||
@@ -27,7 +28,7 @@ namespace Svelto.ECS | |||
} | |||
else | |||
{ | |||
Svelto.Utilities.Console.LogError("Entity ".FastConcat(" with not found ID is about to be removed: ") | |||
Utilities.Console.LogError("Entity ".FastConcat(" with not found ID is about to be removed: ") | |||
.FastConcat(" id: ") | |||
.FastConcat(entityID.entityID) | |||
.FastConcat(" groupid: ") | |||
@@ -35,7 +36,9 @@ namespace Svelto.ECS | |||
} | |||
} | |||
[Conditional("_USE_IT")] | |||
#if DISABLE_CHECKS | |||
[Conditional("_CHECKS_DISABLED")] | |||
#endif | |||
void CheckRemoveEntityID(EGID entityID, Type entityType, Dictionary<Type, ITypeSafeDictionary> @group, string name) | |||
{ | |||
ITypeSafeDictionary entities; | |||
@@ -43,7 +46,7 @@ namespace Svelto.ECS | |||
{ | |||
if (entities.Has(entityID.entityID) == false) | |||
{ | |||
Svelto.Utilities.Console.LogError("Entity ".FastConcat(name, " with not found ID is about to be removed: ") | |||
Utilities.Console.LogError("Entity ".FastConcat(name, " with not found ID is about to be removed: ") | |||
.FastConcat(entityType) | |||
.FastConcat(" id: ") | |||
.FastConcat(entityID.entityID) | |||
@@ -53,7 +56,7 @@ namespace Svelto.ECS | |||
} | |||
else | |||
{ | |||
Svelto.Utilities.Console.LogError("Entity ".FastConcat(name, " with not found ID is about to be removed: ") | |||
Utilities.Console.LogError("Entity ".FastConcat(name, " with not found ID is about to be removed: ") | |||
.FastConcat(entityType) | |||
.FastConcat(" id: ") | |||
.FastConcat(entityID.entityID) | |||
@@ -62,7 +65,9 @@ namespace Svelto.ECS | |||
} | |||
} | |||
[Conditional("_USE_IT")] | |||
#if DISABLE_CHECKS | |||
[Conditional("_CHECKS_DISABLED")] | |||
#endif | |||
void CheckAddEntityID<T>(EGID entityID, T descriptorEntity) where T:IEntityDescriptor | |||
{ | |||
Dictionary<Type, ITypeSafeDictionary> @group; | |||
@@ -78,7 +83,9 @@ namespace Svelto.ECS | |||
} | |||
} | |||
[Conditional("_USE_IT")] | |||
#if DISABLE_CHECKS | |||
[Conditional("_CHECKS_DISABLED")] | |||
#endif | |||
static void CheckAddEntityID(EGID entityID, Type entityType, Dictionary<Type, ITypeSafeDictionary> @group, string name) | |||
{ | |||
ITypeSafeDictionary entities; | |||
@@ -86,7 +93,7 @@ namespace Svelto.ECS | |||
{ | |||
if (entities.Has(entityID.entityID) == true) | |||
{ | |||
Svelto.Utilities.Console.LogError("Entity ".FastConcat(name, " with used ID is about to be built: ") | |||
Utilities.Console.LogError("Entity ".FastConcat(name, " with used ID is about to be built: ") | |||
.FastConcat(entityType) | |||
.FastConcat(" id: ") | |||
.FastConcat(entityID.entityID) | |||
@@ -39,17 +39,21 @@ namespace Svelto.ECS.Internal | |||
{ | |||
int count; | |||
var buffer = (entities as TypeSafeDictionary<TValue>).GetValuesArray(out count); | |||
try | |||
for (var i = 0; i < count; i++) | |||
{ | |||
for (var i = 0; i < count; i++) | |||
int idEntityId = 0; | |||
try | |||
{ | |||
Add(buffer[i].ID.entityID, ref buffer[i]); | |||
idEntityId = buffer[i].ID.entityID; | |||
Add(idEntityId, ref buffer[i]); | |||
} | |||
catch (Exception e) | |||
{ | |||
throw new TypeSafeDictionaryException("trying to add an EntityView with the same ID more than once Entity: ". | |||
FastConcat(typeof(TValue)).FastConcat("id ").FastConcat(idEntityId), e); | |||
} | |||
} | |||
catch (Exception e) | |||
{ | |||
throw new TypeSafeDictionaryException(e); | |||
} | |||
} | |||
@@ -126,9 +130,7 @@ namespace Svelto.ECS.Internal | |||
TValue[] values = GetValuesArray(out count); | |||
for (int i = 0; i < count; i++) | |||
{ | |||
RemoveEntityViewFromEngines(entityViewEnginesDB, ref values[i]); | |||
} | |||
} | |||
public ITypeSafeDictionary Create() | |||
@@ -4,7 +4,8 @@ namespace Svelto.ECS | |||
{ | |||
public class TypeSafeDictionaryException : Exception | |||
{ | |||
public TypeSafeDictionaryException(Exception exception) : base("trying to add an EntityView with the same ID more than once", exception) | |||
public TypeSafeDictionaryException(string message, Exception exception) : | |||
base(message, exception) | |||
{ | |||
} | |||
} |
@@ -3,9 +3,9 @@ using System.Collections.Generic; | |||
namespace Svelto.ECS | |||
{ | |||
public struct EGID:IEquatable<long>,IEqualityComparer<long> | |||
public struct EGID:IEquatable<long>,IEqualityComparer<long>,IComparable<long> | |||
{ | |||
long _GID; | |||
readonly long _GID; | |||
public int entityID | |||
{ | |||
@@ -56,5 +56,10 @@ namespace Svelto.ECS | |||
{ | |||
return _GID.GetHashCode(); | |||
} | |||
public int CompareTo(long other) | |||
{ | |||
return _GID.CompareTo(other); | |||
} | |||
} | |||
} |
@@ -75,7 +75,7 @@ namespace Svelto.ECS | |||
{ | |||
var entityViewsToBuild = EntityDescriptorTemplate<T>.descriptor.entitiesToBuild; | |||
var count = entityViewsToBuild.Length; | |||
//reserve space in the database | |||
Dictionary<Type, ITypeSafeDictionary> @group; | |||
if (_groupEntityDB.TryGetValue(groupID, out group) == false) | |||
@@ -37,7 +37,7 @@ namespace Svelto.ECS | |||
public void PreallocateEntitySpace<T>(ExclusiveGroup.ExclusiveGroupStruct groupStructId, int size) where T : IEntityDescriptor, new() | |||
{ | |||
_weakEngine.Target.Preallocate<T>((int)groupStructId, size); | |||
_weakEngine.Target.Preallocate<T>(groupStructId, size); | |||
} | |||
} | |||
} |
@@ -17,69 +17,79 @@ namespace Svelto.ECS | |||
{ | |||
void SubmitEntityViews() | |||
{ | |||
using (new PlatformProfiler("Svelto.ECS").Sample("Entities submit")) | |||
using (var profiler = new PlatformProfiler("Svelto.ECS - Entities Submission")) | |||
{ | |||
if (_entitiesOperations.Count > 0) | |||
{ | |||
#if DEBUG && !PROFILER | |||
_entitiesOperationsDebug.Clear(); | |||
#endif | |||
_transientEntitiesOperations.FastClear(); | |||
_transientEntitiesOperations.AddRange(_entitiesOperations); | |||
_entitiesOperations.FastClear(); | |||
var entitiesOperations = _transientEntitiesOperations.ToArrayFast(); | |||
for (var i = 0; i < _transientEntitiesOperations.Count; i++) | |||
using (profiler.Sample("Remove and Swap")) | |||
{ | |||
try | |||
#if DEBUG && !PROFILER | |||
_entitiesOperationsDebug.Clear(); | |||
#endif | |||
_transientEntitiesOperations.FastClear(); | |||
_transientEntitiesOperations.AddRange(_entitiesOperations); | |||
_entitiesOperations.FastClear(); | |||
var entitiesOperations = _transientEntitiesOperations.ToArrayFast(); | |||
for (var i = 0; i < _transientEntitiesOperations.Count; i++) | |||
{ | |||
switch (entitiesOperations[i].type) | |||
try | |||
{ | |||
case EntitySubmitOperationType.Swap: | |||
SwapEntityGroup(entitiesOperations[i].builders, | |||
entitiesOperations[i].entityDescriptor, 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), | |||
entitiesOperations[i].entityDescriptor); | |||
break; | |||
case EntitySubmitOperationType.RemoveGroup: | |||
RemoveGroupAndEntitiesFromDB(entitiesOperations[i].fromGroupID); | |||
break; | |||
switch (entitiesOperations[i].type) | |||
{ | |||
case EntitySubmitOperationType.Swap: | |||
SwapEntityGroup(entitiesOperations[i].builders, | |||
entitiesOperations[i].entityDescriptor, | |||
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), | |||
entitiesOperations[i].entityDescriptor); | |||
break; | |||
case EntitySubmitOperationType.RemoveGroup: | |||
RemoveGroupAndEntitiesFromDB(entitiesOperations[i].fromGroupID); | |||
break; | |||
} | |||
} | |||
} | |||
catch (Exception e) | |||
{ | |||
#if DEBUG && !PROFILER | |||
var str = "Entity Operation is ".FastConcat(entitiesOperations[i].type.ToString()) | |||
.FastConcat(" id: ") | |||
.FastConcat(entitiesOperations[i].id) | |||
.FastConcat(" from groupid: ") | |||
.FastConcat(entitiesOperations[i].fromGroupID) | |||
.FastConcat(" to groupid: ") | |||
.FastConcat(entitiesOperations[i].toGroupID); | |||
catch (Exception e) | |||
{ | |||
#if DEBUG && !PROFILER | |||
var str = "Entity Operation is ".FastConcat(entitiesOperations[i].type.ToString()) | |||
.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)); | |||
Console.LogError(e.Message.FastConcat(" ", str, " ", entitiesOperations[i].trace)); | |||
#else | |||
Console.LogException(e); | |||
Console.LogException(e); | |||
#endif | |||
} | |||
} | |||
} | |||
} | |||
try | |||
{ | |||
if (_groupedEntityToAdd.current.Count > 0) | |||
{ | |||
//use other as source from now on current will be use to write new entityViews | |||
_groupedEntityToAdd.Swap(); | |||
using (profiler.Sample("Add")) | |||
{ | |||
//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); | |||
//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); | |||
} | |||
} | |||
} | |||
catch (Exception e) | |||
@@ -90,6 +90,16 @@ namespace Svelto.ECS.Internal | |||
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<T>(new EGID(id, group), out index, out array); | |||
} | |||
public T QueryEntityView<T>(EGID entityGID) where T : class, IEntityStruct | |||
{ | |||
T entityView; | |||
@@ -1,14 +1,13 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
#if !DEBUG || PROFILER | |||
#define DISABLE_CHECKS | |||
using System.Diagnostics; | |||
#endif | |||
using System.Reflection; | |||
using System; | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
using Svelto.Utilities; | |||
using System.Reflection; | |||
#if DEBUG && !PROFILER | |||
#define _USE_IT | |||
#endif | |||
namespace Svelto.ECS | |||
{ | |||
@@ -21,12 +20,12 @@ namespace Svelto.ECS | |||
CheckFields(ENTITY_VIEW_TYPE); | |||
if (needsReflection == true) | |||
{ | |||
EntityView<T>.InitCache(); | |||
} | |||
} | |||
[Conditional("_USE_IT")] | |||
#if DISABLE_CHECKS | |||
[Conditional("_CHECKS_DISABLED")] | |||
#endif | |||
static void CheckFields(Type type) | |||
{ | |||
if (needsReflection == false && ENTITY_VIEW_TYPE != typeof(EntityInfoView)) | |||
@@ -83,6 +83,8 @@ namespace Svelto.ECS | |||
/// <returns></returns> | |||
T[] QueryEntitiesAndIndex<T>(EGID entityGid, out uint index) where T : IEntityStruct; | |||
bool TryQueryEntitiesAndIndex<T>(EGID entityGid, out uint index, out T[] array) where T : IEntityStruct; | |||
T[] QueryEntitiesAndIndex<T>(int id, ExclusiveGroup.ExclusiveGroupStruct group, out uint index) where T : IEntityStruct; | |||
bool TryQueryEntitiesAndIndex<T>(int id, ExclusiveGroup.ExclusiveGroupStruct group, out uint index, out T[] array) where T : 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 | |||
@@ -99,7 +99,7 @@ namespace Svelto.ECS | |||
/// </summary> | |||
public class Sequencer<S> where S: Sequencer<S>, new() | |||
{ | |||
public void SetSequence(Steps steps) | |||
protected void SetSequence(Steps steps) | |||
{ | |||
_steps = steps; | |||
} | |||