using System; using System.Collections.Generic; using System.Reflection; using Svelto.DataStructures; using Svelto.ECS.Hybrid; using Svelto.ECS.Internal; using Svelto.Utilities; namespace Svelto.ECS { public class EntityBuilder : IEntityBuilder where T : struct, IEntityStruct { static class EntityView { internal static readonly FasterList>> cachedFields; internal static readonly Dictionary cachedTypes; #if DEBUG && !PROFILER internal static readonly Dictionary> implementorsByType; #else internal static readonly Dictionary implementorsByType; #endif static EntityView() { cachedFields = new FasterList>>(); var type = typeof(T); var fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance); for (var i = fields.Length - 1; i >= 0; --i) { var field = fields[i]; var setter = FastInvoke.MakeSetter(field); cachedFields.Add(new KeyValuePair>(field.FieldType, setter)); } cachedTypes = new Dictionary(); #if DEBUG && !PROFILER implementorsByType = new Dictionary>(); #else implementorsByType = new Dictionary(); #endif } internal static void InitCache() {} internal static void BuildEntityView(out T entityView) { entityView = new T(); } } public EntityBuilder() { _initializer = DEFAULT_IT; EntityBuilderUtilities.CheckFields(ENTITY_VIEW_TYPE, NEEDS_REFLECTION); if (NEEDS_REFLECTION) EntityView.InitCache(); } public EntityBuilder(in T initializer) : this() { _initializer = initializer; } public void BuildEntityAndAddToList(ref ITypeSafeDictionary dictionary, EGID egid, IEnumerable implementors) { if (dictionary == null) dictionary = new TypeSafeDictionary(); var castedDic = dictionary as TypeSafeDictionary; if (NEEDS_REFLECTION) { DBC.ECS.Check.Require(implementors != null, $"Implementors not found while building an EntityView `{typeof(T)}`"); DBC.ECS.Check.Require(castedDic.ContainsKey(egid.entityID) == false, $"building an entity with already used entity id! id: '{(ulong) egid}', {ENTITY_VIEW_NAME}"); EntityView.BuildEntityView(out var entityView); this.FillEntityView(ref entityView, entityViewBlazingFastReflection, implementors, EntityView.implementorsByType, EntityView.cachedTypes); castedDic.Add(egid.entityID, entityView); } else { DBC.ECS.Check.Require(!castedDic.ContainsKey(egid.entityID), $"building an entity with already used entity id! id: '{egid.entityID}'"); castedDic.Add(egid.entityID, _initializer); } } ITypeSafeDictionary IEntityBuilder.Preallocate(ref ITypeSafeDictionary dictionary, uint size) { return Preallocate(ref dictionary, size); } static ITypeSafeDictionary Preallocate(ref ITypeSafeDictionary dictionary, uint size) { if (dictionary == null) dictionary = new TypeSafeDictionary(size); else dictionary.SetCapacity(size); return dictionary; } public Type GetEntityType() { return ENTITY_VIEW_TYPE; } static EntityBuilder() { ENTITY_VIEW_TYPE = typeof(T); DEFAULT_IT = default; NEEDS_REFLECTION = typeof(IEntityViewStruct).IsAssignableFrom(ENTITY_VIEW_TYPE); HAS_EGID = typeof(INeedEGID).IsAssignableFrom(ENTITY_VIEW_TYPE); ENTITY_VIEW_NAME = ENTITY_VIEW_TYPE.ToString(); SetEGIDWithoutBoxing.Warmup(); } readonly T _initializer; static FasterList>> entityViewBlazingFastReflection => EntityView.cachedFields; internal static readonly Type ENTITY_VIEW_TYPE; public static readonly bool HAS_EGID; static readonly T DEFAULT_IT; static readonly bool NEEDS_REFLECTION; static readonly string ENTITY_VIEW_NAME; } }