using System; using Svelto.Common; using Svelto.DataStructures; using Svelto.ECS.Internal; using Svelto.ECS.Schedulers; namespace Svelto.ECS { public partial class EnginesRoot { readonly FasterList _transientEntitiesOperations; void SubmitEntityViews() { using (var profiler = new PlatformProfiler("Svelto.ECS - Entities Submission")) { int iterations = 0; do { SingleSubmission(profiler); } while ((_groupedEntityToAdd.currentEntitiesCreatedPerGroup.Count > 0 || _entitiesOperations.Count > 0) && ++iterations < 5); #if DEBUG && !PROFILER if (iterations == 5) throw new ECSException("possible circular submission detected"); #endif } } void SingleSubmission(in PlatformProfiler profiler) { if (_entitiesOperations.Count > 0) { using (profiler.Sample("Remove and Swap operations")) { _transientEntitiesOperations.FastClear(); var entitySubmitOperations = _entitiesOperations.GetValuesArray(out var count); _transientEntitiesOperations.AddRange(entitySubmitOperations, count); _entitiesOperations.FastClear(); var entitiesOperations = _transientEntitiesOperations.ToArrayFast(); for (var i = 0; i < _transientEntitiesOperations.Count; i++) { try { switch (entitiesOperations[i].type) { case EntitySubmitOperationType.Swap: MoveEntityFromAndToEngines(entitiesOperations[i].builders, entitiesOperations[i].fromID, entitiesOperations[i].toID); break; case EntitySubmitOperationType.Remove: MoveEntityFromAndToEngines(entitiesOperations[i].builders, entitiesOperations[i].fromID, null); break; case EntitySubmitOperationType.RemoveGroup: RemoveGroupAndEntitiesFromDB( entitiesOperations[i].fromID.groupID, profiler); break; } } catch (Exception e) { var str = "Crash while executing Entity Operation " .FastConcat(entitiesOperations[i].type.ToString()); throw new ECSException(str.FastConcat(" ") #if DEBUG && !PROFILER .FastConcat(entitiesOperations[i].trace.ToString()) #endif , e); } } } } _groupedEntityToAdd.Swap(); if (_groupedEntityToAdd.otherEntitiesCreatedPerGroup.Count > 0) { using (profiler.Sample("Add operations")) { try { AddEntityViewsToTheDBAndSuitableEngines(profiler); } finally { using (profiler.Sample("clear operates double buffering")) { //other can be cleared now, but let's avoid deleting the dictionary every time _groupedEntityToAdd.ClearOther(); } } } } } void AddEntityViewsToTheDBAndSuitableEngines(in PlatformProfiler profiler) { using (profiler.Sample("Add entities to database")) { //each group is indexed by entity view type. for each type there is a dictionary indexed by entityID foreach (var groupOfEntitiesToSubmit in _groupedEntityToAdd.otherEntitiesCreatedPerGroup) { var groupID = groupOfEntitiesToSubmit.Key; //if the group doesn't exist in the current DB let's create it first if (_groupEntityViewsDB.TryGetValue(groupID, out var groupDB) == false) groupDB = _groupEntityViewsDB[groupID] = new FasterDictionary, ITypeSafeDictionary>(); //add the entityViews in the group foreach (var entityViewsToSubmit in _groupedEntityToAdd.other[groupID]) { var type = entityViewsToSubmit.Key; var typeSafeDictionary = entityViewsToSubmit.Value; var wrapper = new RefWrapper(type); if (groupDB.TryGetValue(wrapper, out var dbDic) == false) dbDic = groupDB[wrapper] = typeSafeDictionary.Create(); //Fill the DB with the entity views generate this frame. dbDic.AddEntitiesFromDictionary(typeSafeDictionary, groupID); if (_groupsPerEntity.TryGetValue(wrapper, out var groupedGroup) == false) groupedGroup = _groupsPerEntity[wrapper] = new FasterDictionary(); 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 using (profiler.Sample("Add entities to engines")) { foreach (var groupToSubmit in _groupedEntityToAdd.otherEntitiesCreatedPerGroup) { var groupID = groupToSubmit.Key; var groupDB = _groupEntityViewsDB[groupID]; foreach (var entityViewsToSubmit in _groupedEntityToAdd.other[groupID]) { var realDic = groupDB[new RefWrapper(entityViewsToSubmit.Key)]; entityViewsToSubmit.Value.AddEntitiesToEngines(_reactiveEnginesAddRemove, realDic, in profiler, new ExclusiveGroup.ExclusiveGroupStruct(groupToSubmit.Key)); } } } } DoubleBufferedEntitiesToAdd _groupedEntityToAdd; readonly IEntitySubmissionScheduler _scheduler; readonly FasterDictionary _entitiesOperations; } }