/// <summary> /// Note: unluckily I didn't design the serialization system to be component order independent, so unless /// I do something about it, this method cannot be optimized, the logic of the component order must stay /// untouched (no reordering, no use of dictionaries). Components order must stay as it comes, as /// well as extracomponents order. /// Speed, however, is not a big issue for this class, as the data is always composed once per entity descriptor /// at static constructor time /// </summary> /// <returns></returns> IComponentBuilder[] Construct(int extraComponentsLength, IComponentBuilder[] extraComponents) { IComponentBuilder[] MergeLists (IComponentBuilder[] startingComponents, IComponentBuilder[] newComponents, int newComponentsLength) { var startComponents = new FasterDictionary <RefWrapper <IComponentBuilder, ComponentBuilderComparer>, IComponentBuilder>(); var xtraComponents = new FasterDictionary <RefWrapper <IComponentBuilder, ComponentBuilderComparer>, IComponentBuilder>(); for (uint i = 0; i < startingComponents.Length; i++) { startComponents [new RefWrapper <IComponentBuilder, ComponentBuilderComparer>(startingComponents[i])] = startingComponents[i]; } for (uint i = 0; i < newComponentsLength; i++) { xtraComponents[new RefWrapper <IComponentBuilder, ComponentBuilderComparer>(newComponents[i])] = newComponents[i]; } xtraComponents.Exclude(startComponents); if (newComponentsLength != xtraComponents.count) { newComponentsLength = xtraComponents.count; uint index = 0; foreach (var couple in xtraComponents) { newComponents[index++] = couple.key.type; } } IComponentBuilder[] componentBuilders = new IComponentBuilder[newComponentsLength + startingComponents.Length]; Array.Copy(startingComponents, 0, componentBuilders, 0, startingComponents.Length); Array.Copy(newComponents, 0, componentBuilders, startingComponents.Length, newComponentsLength); var entityInfoComponentIndex = FetchEntityInfoComponent(componentBuilders); DBC.ECS.Check.Assert(entityInfoComponentIndex != -1); componentBuilders[entityInfoComponentIndex] = new ComponentBuilder <EntityInfoComponent>( new EntityInfoComponent { componentsToBuild = componentBuilders }); return(componentBuilders); } if (extraComponentsLength == 0) { return(_componentsToBuild); } var safeCopyOfExtraComponents = new IComponentBuilder[extraComponentsLength]; Array.Copy(extraComponents, safeCopyOfExtraComponents, extraComponentsLength); return(MergeLists(_componentsToBuild, safeCopyOfExtraComponents, extraComponentsLength)); }
internal static void SetEntityViewComponentImplementors <T>(this IComponentBuilder componentBuilder, ref T entityComponent, IEnumerable <object> implementors, ComponentBuilder <T> .EntityViewComponentCache localCache) where T : struct, IBaseEntityComponent { DBC.ECS.Check.Require(implementors != null, NULL_IMPLEMENTOR_ERROR.FastConcat(" entityComponent ", componentBuilder.GetEntityComponentType().ToString())); var cachedTypeInterfaces = localCache.cachedTypes; var implementorsByType = localCache.implementorsByType; var entityComponentBlazingFastReflection = localCache.cachedFields; foreach (var implementor in implementors) { DBC.ECS.Check.Require(implementor != null, "invalid null implementor used to build an entity"); { var type = implementor.GetType(); //fetch all the interfaces that the implementor implements if (cachedTypeInterfaces.TryGetValue(type, out var interfaces) == false) { interfaces = cachedTypeInterfaces[type] = type.GetInterfacesEx(); } for (var iindex = 0; iindex < interfaces.Length; iindex++) { var componentType = interfaces[iindex]; //an implementor can implement multiple interfaces, so for each interface we reference //the implementation object. Multiple entity view component fields can then be implemented //by the same implementor #if DEBUG && !PROFILE_SVELTO if (implementorsByType.TryGetValue(componentType, out var implementorData)) { implementorData.numberOfImplementations++; implementorsByType[componentType] = implementorData; } else { implementorsByType[componentType] = new ECSTuple <object, int>(implementor, 1); } #else implementorsByType[componentType] = implementor; #endif } } } //efficient way to collect the fields of every EntityComponentType var setters = FasterList <KeyValuePair <Type, FastInvokeActionCast <T> > > .NoVirt.ToArrayFast( entityComponentBlazingFastReflection, out var count); for (var i = 0; i < count; i++) { var fieldSetter = setters[i]; var fieldType = fieldSetter.Key; #if DEBUG && !PROFILE_SVELTO ECSTuple <object, int> implementor; #else object implementor; #endif if (implementorsByType.TryGetValue(fieldType, out implementor) == false) { var e = new ECSException(NOT_FOUND_EXCEPTION + " Component Type: " + fieldType.Name + " - EntityComponent: " + componentBuilder.GetEntityComponentType().Name); throw e; } #if DEBUG && !PROFILE_SVELTO if (implementor.numberOfImplementations > 1) { throw new ECSException(DUPLICATE_IMPLEMENTOR_ERROR.FastConcat( "Component Type: ", fieldType.Name, " implementor: ", implementor.instance.ToString()) + " - EntityComponent: " + componentBuilder.GetEntityComponentType().Name); } #endif #if DEBUG && !PROFILE_SVELTO fieldSetter.Value(ref entityComponent, implementor.instance); #else fieldSetter.Value(ref entityComponent, implementor); #endif } implementorsByType.Clear(); }