using System; using System.Collections.Generic; using Svelto.DataStructures; using Svelto.Utilities; namespace Svelto.ECS { #if DEBUG && !PROFILE_SVELTO struct ECSTuple { public readonly T1 instance; public T2 numberOfImplementations; public ECSTuple(T1 implementor, T2 v) { instance = implementor; numberOfImplementations = v; } } #endif static class EntityComponentUtility { const string DUPLICATE_IMPLEMENTOR_ERROR = "Svelto.ECS the same component is implemented with more than one implementor. This is " + "considered an error and MUST be fixed. "; const string NULL_IMPLEMENTOR_ERROR = "Svelto.ECS Null implementor, please be careful about the implementors passed to avoid " + "performance loss "; const string NOT_FOUND_EXCEPTION = "Svelto.ECS Implementor not found for an EntityComponent. "; public static void SetEntityViewComponentImplementors (this IComponentBuilder componentBuilder, ref T entityComponent , FasterList>> entityComponentBlazingFastReflection , IEnumerable implementors #if DEBUG && !PROFILE_SVELTO ,Dictionary> implementorsByType #else , Dictionary implementorsByType #endif , Dictionary cachedTypeInterfaces) { DBC.ECS.Check.Require(implementors != null, NULL_IMPLEMENTOR_ERROR.FastConcat(" entityComponent " , componentBuilder .GetEntityComponentType().ToString())); 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(implementor, 1); #else implementorsByType[componentType] = implementor; #endif } } } //efficient way to collect the fields of every EntityComponentType var setters = FasterList>>.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 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(); } } }