/// <summary> /// Preallocate memory to avoid the impact to resize arrays when many entities are submitted at once /// </summary> void Preallocate(ExclusiveGroupStruct groupID, uint numberOfEntities, IComponentBuilder[] entityComponentsToBuild) { void PreallocateEntitiesToAdd() { _groupedEntityToAdd.Preallocate(groupID, numberOfEntities, entityComponentsToBuild); } void PreallocateDBGroup() { var numberOfEntityComponents = entityComponentsToBuild.Length; FasterDictionary <RefWrapperType, ITypeSafeDictionary> group = GetOrCreateDBGroup(groupID); for (var index = 0; index < numberOfEntityComponents; index++) { var entityComponentBuilder = entityComponentsToBuild[index]; var entityComponentType = entityComponentBuilder.GetEntityComponentType(); var refWrapper = new RefWrapperType(entityComponentType); var dbList = group.GetOrCreate(refWrapper, () => entityComponentBuilder.CreateDictionary(numberOfEntities)); entityComponentBuilder.Preallocate(dbList, numberOfEntities); if (_groupsPerEntity.TryGetValue(refWrapper, out var groupedGroup) == false) { groupedGroup = _groupsPerEntity[refWrapper] = new FasterDictionary <ExclusiveGroupStruct, ITypeSafeDictionary>(); } groupedGroup[groupID] = dbList; } } PreallocateDBGroup(); PreallocateEntitiesToAdd(); _entityLocator.PreallocateReferenceMaps(groupID, numberOfEntities); }
///-------------------------------------------- void Preallocate <T>(ExclusiveGroupStruct groupID, uint size) where T : IEntityDescriptor, new() { using (var profiler = new PlatformProfiler("Preallocate")) { var entityComponentsToBuild = EntityDescriptorTemplate <T> .descriptor.componentsToBuild; var numberOfEntityComponents = entityComponentsToBuild.Length; FasterDictionary <RefWrapperType, ITypeSafeDictionary> group = GetOrCreateGroup(groupID, profiler); for (var index = 0; index < numberOfEntityComponents; index++) { var entityComponentBuilder = entityComponentsToBuild[index]; var entityComponentType = entityComponentBuilder.GetEntityComponentType(); var refWrapper = new RefWrapperType(entityComponentType); if (group.TryGetValue(refWrapper, out var dbList) == false) { group[refWrapper] = entityComponentBuilder.Preallocate(ref dbList, size); } else { dbList.SetCapacity(size); } if (_groupsPerEntity.TryGetValue(refWrapper, out var groupedGroup) == false) { groupedGroup = _groupsPerEntity[refWrapper] = new FasterDictionary <ExclusiveGroupStruct, ITypeSafeDictionary>(); } groupedGroup[groupID] = dbList; } } }
ref FilterGroup CreateOrGetFilterForGroup (int filterID, ExclusiveGroupStruct groupID, RefWrapperType refWrapper) { var fasterDictionary = _filters.GetOrCreate(refWrapper, () => new FasterDictionary <ExclusiveGroupStruct, GroupFilters>()); GroupFilters filters = fasterDictionary.GetOrCreate( groupID, () => new GroupFilters(new SharedSveltoDictionaryNative <int, FilterGroup>(0), groupID)); return(ref filters.CreateOrGetFilter(filterID)); }
public void AddEngine(IEngine engine) { var type = engine.GetType(); var refWrapper = new RefWrapperType(type); DBC.ECS.Check.Require(engine != null, "Engine to add is invalid or null"); DBC.ECS.Check.Require( _enginesTypeSet.Contains(refWrapper) == false || type.ContainsCustomAttribute(typeof(AllowMultipleAttribute)) == true , "The same engine has been added more than once, if intentional, use [AllowMultiple] class attribute " .FastConcat(engine.ToString())); try { if (engine is IReactOnAddAndRemove viewEngine) { CheckReactEngineComponents(viewEngine, _reactiveEnginesAddRemove); } if (engine is IReactOnDispose viewEngineDispose) { CheckReactEngineComponents(viewEngineDispose, _reactiveEnginesAddRemoveOnDispose); } if (engine is IReactOnSwap viewEngineSwap) { CheckReactEngineComponents(viewEngineSwap, _reactiveEnginesSwap); } if (engine is IReactOnSubmission submissionEngine) { _reactiveEnginesSubmission.Add(submissionEngine); } _enginesTypeSet.Add(refWrapper); _enginesSet.Add(engine); if (engine is IDisposable) { _disposableEngines.Add(engine as IDisposable); } if (engine is IQueryingEntitiesEngine queryableEntityComponentEngine) { queryableEntityComponentEngine.entitiesDB = _entitiesDB; queryableEntityComponentEngine.Ready(); } } catch (Exception e) { throw new ECSException("Code crashed while adding engine ".FastConcat(engine.GetType().ToString(), " ") , e); } }
/// <summary> /// Todo: it would be probably better to split even further the logic between submission and callbacks /// Something to do when I will optimize the callbacks /// </summary> /// <param name="profiler"></param> /// <param name="maxNumberOfOperations"></param> IEnumerator SingleSubmission(PlatformProfiler profiler, uint maxNumberOfOperations) { #if UNITY_NATIVE NativeOperationSubmission(profiler); #endif ClearChecks(); bool entitiesAreSubmitted = false; uint numberOfOperations = 0; if (_entitiesOperations.count > 0) { using (profiler.Sample("Remove and Swap operations")) { _transientEntitiesOperations.FastClear(); _entitiesOperations.CopyValuesTo(_transientEntitiesOperations); _entitiesOperations.FastClear(); EntitySubmitOperation[] entitiesOperations = _transientEntitiesOperations.ToArrayFast(out var count); for (var i = 0; i < 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: RemoveEntitiesFromGroup( entitiesOperations[i].fromID.groupID, profiler); break; case EntitySubmitOperationType.SwapGroup: SwapEntitiesBetweenGroups(entitiesOperations[i].fromID.groupID, entitiesOperations[i].toID.groupID, profiler); break; } } catch { var str = "Crash while executing Entity Operation " .FastConcat(entitiesOperations[i].type.ToString()); Svelto.Console.LogError(str.FastConcat(" ") #if DEBUG && !PROFILE_SVELTO .FastConcat(entitiesOperations[i].trace.ToString()) #endif ); throw; } ++numberOfOperations; if ((uint)numberOfOperations >= (uint)maxNumberOfOperations) { yield return(null); numberOfOperations = 0; } } } entitiesAreSubmitted = true; } _groupedEntityToAdd.Swap(); if (_groupedEntityToAdd.otherEntitiesCreatedPerGroup.count > 0) { using (profiler.Sample("Add operations")) { try { 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 groupToSubmit in _groupedEntityToAdd.otherEntitiesCreatedPerGroup) { var groupID = groupToSubmit.Key; var groupDB = GetOrCreateGroup(groupID, profiler); //add the entityComponents in the group foreach (var entityComponentsToSubmit in _groupedEntityToAdd.other[groupID]) { var type = entityComponentsToSubmit.Key; var targetTypeSafeDictionary = entityComponentsToSubmit.Value; var wrapper = new RefWrapperType(type); ITypeSafeDictionary dbDic = GetOrCreateTypeSafeDictionary(groupID, groupDB, wrapper, targetTypeSafeDictionary); //Fill the DB with the entity components generate this frame. dbDic.AddEntitiesFromDictionary(targetTypeSafeDictionary, groupID); } } } //then submit everything in the engines, so that the DB is up to date with all the entity components //created by the entity built using (profiler.Sample("Add entities to engines")) { foreach (var groupToSubmit in _groupedEntityToAdd.otherEntitiesCreatedPerGroup) { var groupID = groupToSubmit.Key; var groupDB = _groupEntityComponentsDB[groupID]; //entityComponentsToSubmit is the array of components found in the groupID per component type. //if there are N entities to submit, and M components type to add for each entity, this foreach will run NxM times. foreach (var entityComponentsToSubmit in _groupedEntityToAdd.other[groupID]) { var realDic = groupDB[new RefWrapperType(entityComponentsToSubmit.Key)]; entityComponentsToSubmit.Value.ExecuteEnginesAddOrSwapCallbacks(_reactiveEnginesAddRemove, realDic, null, new ExclusiveGroupStruct(groupID), in profiler); numberOfOperations += entityComponentsToSubmit.Value.count; if (numberOfOperations >= maxNumberOfOperations) { yield return(null); numberOfOperations = 0; } } } } } finally { using (profiler.Sample("clear double buffering")) { //other can be cleared now, but let's avoid deleting the dictionary every time _groupedEntityToAdd.ClearOther(); } } } entitiesAreSubmitted = true; } if (entitiesAreSubmitted) { var enginesCount = _reactiveEnginesSubmission.count; for (int i = 0; i < enginesCount; i++) { _reactiveEnginesSubmission[i].EntitiesSubmitted(); } } }
internal EntityFilterID(uint filterID, RefWrapperType componentType) { _filterID = filterID; _componentType = componentType; _hashCode = (int)filterID + (int)filterID ^ componentType.GetHashCode(); }